Алик Кириллович

Хрупкая красота программного кода: десять приёмов программирования, способных её разрушить

26 мая 2009 г.

Здесь — полная авторская версия статьи, опубликованной в журнале «Хабрахабр» в сокращённом виде из-за ограничений на размер материала.

Тема красоты кода для меня очень важна, поэтому буду благодарен всем, кто поставит ссылочку, и за любой другой «пиар» статьи. Если интересно — можете  подписаться на RSS.

 

Для меня программирование — это не только технология, но и, во многом — искусство. И, поэтому, большое значение имеет красота кода.

Последние несколько лет я собирал приёмы программирования, разрушающие в программном коде его утончённую красоту:

  1. Объявление всех переменных в начале программы;

  2. Возврат результата функции через её параметр;

  3. Отсутствие локальных функций;

  4. Отсутствие else if;

  5. Использование параллельных массивов;

  6. Обязательное хранение размера массива в отдельной переменной;

  7. Доступ к свойствам объекта через obj.getProperty() и obj.setProperty(value);

  8. Использование рекурсии для вычисления факториалов и Чисел Фибоначчи;

  9. Отсутствие именованных параметров функции;

  10. Невозможность объявления объектов «на лету».

Объявление всех переменных в начале программы

В двух словах:

Переменные должны объявляться в начале логического блока, в котором они используются, а НЕ в начале функции или программы.

Все программные системы иерархичны. Программы делятся на пакеты, пакеты — на классы, классы разбиваются на отдельные функции.

Данные, относящиеся к тому или иному модулю программы, принято объявлять в начале этого модуля. Локальные переменные объявляются в начале функции; свойства, относящиеся ко всему классу, объявляются в начале определения класса и т.д.

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

Однако эти блоки — полноценные элементы в иерархии программы. И они тоже имеют право на собственные «локальные» переменные! Которые объявляются в начале этого блока и используются только в его пределах.

Пример:

Предположим, нам надо написать функцию сортировки массива методом слияния.

Алгоритм сортировки слиянием состоит из следующих шагов:

  1. Если длина массива = 2, то:
    1. просто меняем местами эти два элемента в случае неправильного их расположения.

  2. Если длина массива > 2, то:
    1. разбиваем массив на две половины: левый и правый подмассивы;

    2. отдельно сортируем каждый подмассив (рекурсивно);

    3. сливаем эти два отсортированных подмассива в один отсортированный результирующий массив.

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

Однако, они являются полноправными элементами иерархии программы, и решают свои собственные маленькие подзадачи.

Поэтому:

В начале функции объявляются переменные, относящиеся ко всей функции, например: intLeftIndex, intRightIndex, intLength.

А переменные, относящиеся к отдельным её блокам, объявляются в начале соответствующего блока, например: elTemp объявляется в начале блока сортировки массива из 2-х элментов; intCenterIndex — в начале блока разбиения; arSortedSubarray и intLeftElIndex — в начале блока слияния.

            /*
            Эта функция реализует сортировку слиянием
            */
            function mergeSort (arArryay, intLeftIndex, intRightIndex)
              {
              /*
              Здесь объявляются переменные, относящиеся ко ВСЕЙ ФУНКЦИИ.
              
              Переменные, относящиеся к отдельным её блокам,
              объявляются в начале соответствующего блока.
              */
              intLeftIndex  = intLeftIndex  || 0;
              intRightIndex = intRightIndex || arArryay.length-1;
              var intLength = intRightIndex - intLeftIndex + 1;
              
              if (intLength == 2)
                {
                /*
                БЛОК КОДА: сортировка массива из 2-х элементов
                */
                if (arArryay [intRightIndex] < arArryay [intLeftIndex])
                  {
                  var elTemp = arArryay [intRightIndex];
                  arArryay [intRightIndex] = arArryay [intLeftIndex];
                  arArryay [intLeftIndex]  = elTemp;
                  }
                }
              else if (intLength > 2)
                {
                /*
                БЛОК КОДА: разбиение массива на два подмассива
                */
                var intCenterIndex = intLeftIndex + Math.ceil (intLength / 2) - 1;
                var intLeftSubarrayLength  = intCenterIndex - intLeftIndex + 1;
                var intRightSubarrayLength = intRightIndex  - intCenterIndex;
                
                /*
                БЛОК КОДА: рекурсивная сортировка каждого подмассива
                */
                mergeSort (arArryay, intLeftIndex,     intCenterIndex);
                mergeSort (arArryay, intCenterIndex+1, intRightIndex);
                
                /*
                БЛОК КОДА: слияние
                */
                var arSortedSubarray = [];
                var intLeftElIndex = intLeftIndex;
                var intRihtElIndex = intCenterIndex+1;
                while (intLeftElIndex <= intCenterIndex || intRihtElIndex <= intRightIndex)
                  {
                  if (intRihtElIndex <= intRightIndex && (arArryay [intRihtElIndex] <= arArryay [intLeftElIndex] || intLeftElIndex > intCenterIndex))
                    {
                    arSortedSubarray [arSortedSubarray.length] = arArryay [intRihtElIndex];
                    intRihtElIndex++;
                    }
                  if (intLeftElIndex <= intCenterIndex && (arArryay [intLeftElIndex] <= arArryay [intRihtElIndex] || intRihtElIndex > intRightIndex))
                    {
                    arSortedSubarray [arSortedSubarray.length] = arArryay [intLeftElIndex];
                    intLeftElIndex++;
                    }
                  }
                  
                for (var i = 0; i < intLength; i++)
                  {
                  arArryay [intLeftIndex + i] = arSortedSubarray [i];
                  }
                }
              }
          

И поэтому:

Объявление всех переменных в начале функции — страшное зло [1].

Это приводит к смешению переменных, относящихся ко всей функции, с переменными, относящимися только к её отдельному блоку.

Это разрывает блок на две части: объявления данных (в начале функции) и использования этих данных (в самом блоке).

Это усложняет комментирование блока: в одном месте мы комментируем переменные, но не знаем, как их использовать; в другом месте мы комментируем алгоритм, но не знаем, с какими данными он работает.

Пример:

В случае объявления всех переменных в начале функции, переменные, относящиеся ко всей функции, перемешаются с переменными, имеющими смысл только внутри отдельных её блоков.

            function mergeSort (arArryay, intLeftIndex, intRightIndex)
              {
              /*
              Угадайте: какие из этих переменных относятся ко всей функции,
              а какие — к отдельным её блокам?
              */
              var intLength,
                  elTemp,
                  intCenterIndex,
                  intLeftSubarrayLength,
                  intRightSubarrayLength,
                  arSortedSubarray,
                  intLeftElIndex,
                  intRihtElIndex,
                  i;
              intLeftIndex  = intLeftIndex  || 0;
              intRightIndex = intRightIndex || arArryay.length-1;
              intLength = intRightIndex - intLeftIndex + 1;
              if (intLength == 2)
                {
                if (arArryay [intRightIndex] < arArryay [intLeftIndex])
                  {
                  elTemp = arArryay [intRightIndex];
                  arArryay [intRightIndex] = arArryay [intLeftIndex];
                  arArryay [intLeftIndex] = elTemp;
                  }
                }
              else if (intLength > 2)
                {
                intCenterIndex = intLeftIndex + Math.ceil (intLength / 2) - 1;
                intLeftSubarrayLength  = intCenterIndex - intLeftIndex + 1;
                intRightSubarrayLength = intRightIndex - intCenterIndex;
                mergeSort (arArryay, intLeftIndex, intCenterIndex);
                mergeSort (arArryay, intCenterIndex+1, intRightIndex);
                arSortedSubarray = [];
                intLeftElIndex = intLeftIndex;
                intRihtElIndex = intCenterIndex+1;
                
                //...код сокращён...
                }
              }
          
Пример:

Вы только представьте: У нас есть функция в 300 строк кода [2]. Где-нибудь на 200-й строке нам надо поменять две переменные местами. Для этого мы лезем на 200 сток выше в начало функции, объявляем переменную temp, которая не имеет никакого отношения ко всей функции, а используется только один раз в одном месте, потом опять возвращаемся к 200-й строке и меняем переменные местами… По-моему, это просто кошмар.

Хуже всего, что существуют языки, которые считают себя умнее разработчика и заставляют объявлять все переменные в начале функции. Например, такой уважаемый язык как Pascal/Delphi. Чего я ему простить не могу…

Возврат результата функции через её параметр

В двух словах:

Функция должна возвращать результат, зависящий от её параметров, а НЕ принимать результат в качестве аргумента.

Понятие функции (как в математике, так и в программировании) имеет чёткий смысл: вычисление результата, зависящего от аргументов.

В нормальном программном коде ясно видно, что является результатом, а что аргументами: результат = функция (аргумент1, аргумент2).

Однако часто встречается приём, при котором возвращаемое значение передаётся в качестве аргумента функции: функция (аргумент1, аргумент2, &результат).

Этот приём ужасен. При его использовании не видно, от чего функция зависит, а что возвращает.

Чаще всего, в применении этого приёма виноваты не сами разработчики, а языки программирования.

Существуют две основные причины, по которым языки заставляют нас прибегать к этому приёму.

Первая причина состоит в том, что в некоторых языках функции не могут создавать и возвращать сложные объекты.

Пример:

Предположим, что мы хотим на C++ написать функцию, перемножающую две матрицы и возвращающую получившуюся матрицу в качестве результата. Матрицы мы решили представлять в виде двумерного массива.

Но мы не можем объявить в функции результирующий двумерный массив, а затем вернуть его:

            int mtxResult [10][10] = mult (mtxA, mtxB);
          

Поэтому нам придётся сначала вне функции объявить результирующий массив, а затем вызвать функцию перемножения, передав результат в качестве аргумента:

            mult (mtxA, mtxB, mtxResult);
          

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

Пример:

Можно хранить матрицу не в виде двумерного массива, а в виде структуры или объекта:

            Matrix mtxResult = mult (mtxA, mtxB);
          

Код станет менее лаконичным (из-за объявления дополнительных структур), но, зато, гораздо более красивым.

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

Пример:

Предположим, что мы хотим на C++ написать функцию, решающую квадратное уравнение. Функция принимает в качестве аргумента коэффициенты a, b, c и возвращает три результата: число корней, x1 и x2.

Однако вернуть сразу три значения в C++ невозможно:

            intRootsCount, numX1, numX2 = quadraticEquation (numA, numb, numC)
          

Поэтому нам придётся часть результатов выполнения функции передать через указатель в качестве аргументов:

            intRootsCount = quadraticEquation (numA, numB, numC, &numX1, &numX2);
          

Здесь, опять же, от этого приёма можно избавиться, возвращая объект или структуру, хранящую результаты выполнения функции в виде полей.

Пример:

Можно возвращать результаты решения квадратного уравнения в виде структуры с тремя свойствами [3]:

            QuadrEqResult qerResult = quadraticEquation (numA, numB, numC);
            intRootsCount = qerResult.count;
            numX1 = qerResult.x1;   
            numX2 = qerResult.x2;
          

Однако и в первом, и во втором случае, при использовании структур или объектов, мы можем столкнуться с ещё одной проблемой: необходимостью отдельно описывать эти структуры или классы.

Причём во многих языках, например на C++, мы не можем описать структуру или класс внутри самой функции (см. следующий раздел). Нам придётся описывать их отдельно от функции, делая их неподчиненными функции сущностями, что уродует иерархию программы.

Слава богу, в других языках классы можно описывать прямо внутри функции, а, например в JavaScript можно просто возвратить объект, нигде отдельно не описывая его структуру.

Пример:
            function quadraticEquation (numA, numb, numC)
              {
              //...
              return ({
                      count: intRootsCount,
                      x1: intX1,
                      x2: intX2
                      });
              }

            var objResult = quadraticEquation (numA, numB, numC);
            intRootsCount = objResult.count;
            numX1 = objResult.x1;   
            numX2 = objResult.x2;   
          

Вот это настоящая красота!

Отсутствие локальных функций

В двух словах:

Локальная функция должна объявляться внутри функции, которой она логически подчиняется, а НЕ в глобальном контексте.

Как уже говорилось, программные системы (как объектно-ориентированные, так и процедурные) иерархичны и делятся на вложенные друг в друга модули (впрочем, это очевидно).

Каждый из модулей располагает своими локальными ресурсами, используемыми только в рамках этого модуля.

Например, локальные переменные являются ресурсами модуля функции.

Однако ресурсами функции являются не только переменные! Подфункции, классы, структуры и т.д. также являются полноправными ресурсами функции, подчинёнными ей, и используемыми только в её рамках.

Пример:

Предположим, нам надо написать функцию printDossier, печатающую досье.

Сверху и снизу досье должен находиться его номер, выровненный по центру и обрамлённый декоративными свасти звёздочками:

              ****************** 666 ******************
              
              Имя:            Макс Отто фон Штирлиц
              
              Звание:         штандартенфюрер
              
              Национальность: истинный ариец
              
              Характер:       нордический, выдержанный
              
              ****************** 666 ******************
            

Чтобы не дублировать код, печатающий верхний, и печатающий нижний номер, мы решили вынести его в отдельную функцию printNumber.

Функция, печатающая номер досье, является подчинённой по отношению к функции, печатающей всё досье, используется только в её рамках и не имеет самостоятельного смысла. Поэтому, функция printNumber должна быть локальной по отношению к printDossier, и объявляться в её теле.

            #
            #Эта функция печатает досье:
            #
            def printDossier (people):
              
              #
              #Эта локальная функция печатает номер досье:
              #
              def printNumber ():
                #Вычисляем количество звёздочек слева и справа, так, чтобы номер оказался по центру
                stringLength = 32
                numberLength = len (people.number)
                starsCount   = (stringLength - numberLength) / 2
                #Печатаем звёздочки слева, номер досье, и звёздочки справа
                print ('*' * starsCount) + people.number + ('*' * starsCount)
              
              #
              #Печатаем досье
              #
              #Печатаем номер сверху
              printNumber ()
              
              #Печатаем: имя, звание, национальность и характер
              print 'Имя: '+            people.name
              print 'Звание: '+         people.rank
              print 'Национальность: '+ people.race
              print 'Характер: '+       people.character
              
              #Печатаем номер снизу
              printNumber ()
          

Поэтому:

Объявление функций, структур и т.д. вне функции, которой они иерархически подчиняются — очень плохой приём.

Это уродует иерархию программы, делая подчинённую функцию независимой, и иерархически неподчиненной родительской функции сущностью.

Это нарушает принцип сокрытия информации, вынося наружу детали внутренней реализации родительской функции — подчинённую функцию.

Это затрудняет понимание кода, засоряя глобальный контекст лишними сущностями.

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

 

Но многие языки программирования, например C++, не поддерживают локальные функции, классы, структуры и т.д.

Пример:

Поскольку C++ не поддерживает локальные функции, функцию, печатающую номер досье, нам придётся сделать глобальной, независимой и иерархически неподчинающейся функции, печатающей всё досье:

            /*
            Эта функция печатает номер досье.
            
            Мы вынуждены сделать её глобальной,
            хотя она является деталью внутренней реализации функции printDossier
            и не имеет самостоятельного смысла.
            */
            void printNumber ()
              {
              //Вычисляем количество звёздочек слева и справа, так, чтобы номер оказался по центру
              int stringLength = 32;
              int numberLength = strlen (people.number);
              int starsCount   = (stringLength - numberLength) / 2;
              //Печатаем звёздочки слева, номер досье, и звёздочки справа
              for (int i = 0; i < starsCount; i++) cout<<"*";
              cout<<people.number;
              for (int i = 0; i < starsCount; i++) cout<<"*";
              }
          
            /*
            Эта функция печатает досье
            */
            void printDossier (People people)
              {
              /*
              Печатаем досье
              */
              //Печатаем номер сверху
              printNumber ();
              
              //Печатаем: имя, звание, национальность и характер
              cout<< "Имя: "            << people.name;
              cout<< "Звание: "         << people.rank;
              cout<< "Национальность: " << people.race;
              cout<< "Характер: "       << people.character;
              
              //Печатаем номер снизу
              printNumber ();
              }
          

Язык Pascal/Delphi поддерживает локальные функции, но, заставляет их объявлять только в начале функции. Это не так страшно, как объявлять только в начале все переменные, но тоже, иногда, бывает достаточно некрасиво.

Пример:

Предположим, у нас есть функция из нескольких блоков кода, каждый из которых выполняет отдельный шаг всего алгоритма.

Мы решили переписать один их блоков в рекурсивной форме.

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

            program main ();
              function block3 (param: integer): integer;   //      (4)──┐           
              begin                                        //       ↑   ↓           
                Рекурсивный блок кода #3                   //       ↑   ↓           
              end;                                         //       ↑   ↓           
              {}                                           //       ↑   ↓           
              procedure block5 (param: integer);           //       ↑   ↓  (7)──┐   
              begin                                        //       ↑   ↓   ↑   ↓   
                Рекурсивный блок кода #5                   //       ↑   ↓   ↑   ↓   
              end;                                         //       ↑   ↓   ↑   ↓   
              {}                                           //       ↑   ↓   ↑   ↓   
             begin                                         //       ↑   ↓   ↑   ↓   
                блок кода #1                               //  (1)  ↑   ↓   ↑   ↓   
                {}                                         //   ↓   ↑   ↓   ↑   ↓   
                блок кода #2                               //  (2)  ↑   ↓   ↑   ↓   
                {}                                         //   ↓   ↑   ↓   ↑   ↓   
                {Прокручиваем на самый верх                //   ↓   ↑   ↓   ↑   ↓   
                и находим код рекурсивной функции block3}  //   ↓   ↑   ↓   ↑   ↓   
                block3 (param);                            //  (3)──┘   ↓   ↑   ↓   
                {}                                         //           ↓   ↑   ↓   
                блок кода #4                               //          (5)  ↑   ↓   
                {}                                         //           ↓   ↑   ↓   
                {Прокручиваем на самый верх                //           ↓   ↑   ↓   
                и находим код рекурсивной функции block5}  //           ↓   ↑   ↓   
                block5 (param);                            //          (6)──┘   ↓   
                {}                                         //                   ↓   
                блок кода #6                               //                  (8)  
              end.
          

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

К счастью, поддержка локальных функций есть почти во всех «новых» языках, как динамических (JavaScript, Python), так и классических (Java). И надо только воспользоваться этой возможностью.

Отсутствие else if

В двух словах:

Уровень вложенности блока должен соответствовать его иерархическому положению в программе.

Блоки кода, имеющие одинаковый уровень вложенности, относятся к одному уровню иерархии программы. Соответственно, блоки кода с большим уровнем вложенности являются подчинёнными по отношению к блокам с меньшей вложенностью.

Вроде бы, это очевидный факт.

Тем не менее, иногда, особенно в учебной литературе, я встречаю нарушение этого правила:

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

Пример 1:

Предположим, что нам надо приветствовать пользователя, в зависимости от времени суток. Приветствия «Спокойной ночи», «Доброе утро», «Добрый день», и «Добрый вечер» совершенно равноправны и относятся к одному уровню иерархии программы.

Поэтому этот код, где приветствия имеют разный уровень вложенности, страшно уродлив:

            if (numHour >= 0 && numHour < 6)
              {
              print ("Спокойной ночи!");
              }
            else
              {
              if (numHour >= 6 && numHour < 12)
                {
                print ("Доброе утро!");
                }
              else
                {
                if (numHour >= 12 && numHour < 18)
                  {
                  print ("Добрый день!");
                  }
                else
                  {
                  print ("Добрый вечер!");
                  }
                }
              }
          

Его надо переписать так, чтобы равноправные блоки имели равный уровень вложенности:

            if (numHour >= 0 && numHour < 6)
              {
              print ("Спокойной ночи ");
              }
            else if (numHour >= 6 && numHour < 12)
              {
              print ("Доброе утро!");
              }
            else if (numHour >= 12 && numHour < 18)
              {
              print ("Добрый день!");
              }
            else
              {
              print ("Добрый вечер!");
              }
          
Пример 2:

Предположим теперь, что мы должны проверить, зарегистрирован ли пользователь в системе, и, если зарегистрирован, то поприветствовать, а если нет — послать вон.

В данном случае, блоки кода приветствия имеют подчинённый уровень по отношению к блоку «зарегистрирован», а блок «пошёл вон» — подчинённое к блоку «не зарегистрирован». Поэтому уродлив код, в котором все блоки имеют одинаковый уровень вложенности:

            if (!isRegistred ())
              {
              print ("Вы не зарегистрированы в системе. Идите вон!");
              }
            else if (numHour >= 0 && numHour < 6)
              {
              print ("Спокойной ночи ");
              }
            else if (numHour >= 6 && numHour < 12)
              {
              print ("Доброе утро!");
              }
            else if (numHour >= 12 && numHour < 18)
              {
              print ("Добрый день!");
              }
            else
              {
              print ("Добрый вечер!");
              }
          

Его надо переписать так, чтобы уровень вложенности блоков соответствовал их иерархическому положению:

            if (!isRegistred ())
              {
              /*
              Не зарегистрирован
              */
              print ("Вы не зарегистрированы в системе. Идите вон!");
              }
            else
              {
              /*
              Зарегистрирован
              */
              if (numHour >= 0 && numHour < 6)
                {
                print ("Спокойной ночи!");
                }
              else if (numHour >= 6 && numHour < 12)
                {
                print ("Доброе утро!");
                }
              else if (numHour >= 12 && numHour < 18)
                {
                print ("Добрый день!");
                }
              else
                {
                print ("Добрый вечер!");
                }
              }
          

В некоторых старых языках программирования (по-моему, в каких-то древних версиях Паскаля или что-то в этом роде) были операторы if и else, но отсутствовал оператор else if. Они навязывали приём, при котором каждый последующий блок в цепочке сравнений имел всё больший уровень вложенности (как в примере №1).

Но сейчас эти языки вымерли как динозавры, и все нормальные языки поддерживают else if.

Поэтому надо писать код, в котором уровень вложенности соответствует уровню иерархии блока, а также не поддаваться на провокации всяких вредных учебников.

Использование параллельных массивов

В двух словах:

При работе с вложенными данными следует соблюдать правила иерархии: свойства должны храниться внутри объекта, а НЕ объект — внутри свойства.

При работе с вложенными данными следует соблюдать правила иерархии.

Во-первых, связанные данные должны иметь общий контейнер.

Благодаря этому объект выглядит именно как объект, и не распадается на множество независимых свойств.

Также, мы можем работать с объектом как с единым целым, например, передавать его в качестве параметра функции и т.д.

Пример:

В данном примере видно, что lastName, firstName, surName относятся к одному объекту: objPeople1.

            objPeople1.lastName  = "Пупкин";
            objPeople1.firstName = "Василий";
            objPeople1.surName   = "Иванович";
          

Мы можем работать с этим объектом не как с набором свойств, а как с единым целым:

            doSomething (objPeople1);
          

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

Пример:

За время написания статьи Путин успел переехать:

            World.Russia.Moscow./*Kremlin*/WhiteHouse.Putin
          
Пример:

А в данном примере только с помощью иерархического порядка можно определить, что

синий пакет находится в красном:

redBag.blueBag.myThing

…или же красный — в синем:

blueBag.redBag.myThing

В программах на объектно-ориентированных языках это правила иерархии почти всегда соблюдается.

Однако соблюдать правила иерархии при обращении к данным надо не только в объектно-ориентированных языках! Тем не менее, в программах на процедурных языках это правило нередко нарушается.

Одним их вопиющих примеров уродского обращения к данным является использование так называемых параллельных массивов.

Пример:

Предположим нам надо сохранить данные о советских лидерах, содержащие следующие свойства: фамилию, имя и отчество.

Каждое из этих свойств хранится в отдельном массиве:

            char *lastNames  [3] = {"Ленин",    "Сталин",        "Хрущёв"};
            char *firstNames [3] = {"Владимир", "Иосиф",         "Никита"};
            char *surNames   [3] = {"Ильич",    "Виссарионович", "Сергеевич"};
            const lenin = 0, stalin = 1, khrushchev = 2;
          

И обращение к данным происходит следующим образом:

            //Печатаем: "Никита Хрущёв"
            cout<<firstNames[khrushchev]<<" "<<lastNames[khrushchev];
          

При использовании параллельных массивов нарушаются все возможные правила работы с иерархичными данными.

Во-первых, записи распадаются на множество несвязанных полей. Мы не можем работать с записью как с единым объектом.

Пример:

Вместо работы с объектом как с единым целым, нам приходится работать со множеством полей:

            doSomething(lastNames [lenin], lastNames [lenin], surNames [lenin]);
          

Во-вторых, обращение к вложенным данным происходит «задом-наперёд».

Пример:

Запись

            firstNames[khrushchev]
          

означает не Хрущёва, хранящего свойство firstName, а, наоборот, свойство, хранящее внутри себя Хрущёва!

Мне не раз приходилось встречаться с ещё одним приёмом, очень похожим на параллельные массивы: хранение данных в многомерном массиве, где первый индекс отвечает за номер свойства, а второй — за номер записи.

Пример:
            char *leaders [3][3] = 
              {
                {"Ленин",    "Сталин",        "Хрущёв"},
                {"Владимир", "Иосиф",         "Никита"},
                {"Ильич",    "Виссарионович", "Сергеевич"}
              }

            const lenin = 0, stalin = 1, khrushchev = 2;
            const lastName = 0, firstName = 1, surName = 2;
          

Обращение к данным происходит следующим образом:

            leaders [propertyNumber][peopleNumber]
          

Например:

            //Печатаем: "Владимир Ленин"
            cout<< leaders [firstName][lenin]<<" "<< leaders [lastName][lenin];

            //Печатаем: "Никита Хрущёв"
            cout<< leaders [firstName][khrushchev]<<" "<< leaders [lastName][khrushchev];

            //Печатаем: "Иосиф Сталин"
            cout<< leaders [firstName][stalin]<<" "<< leaders [lastName][stalin];
          

Этот приём имеет только одно преимущество по сравнению с параллельными массивами — список всех записей объединён в единый объект. Однако все остальные недостатки параллельных массивов никуда не деваются:

Во-первых, записи, по прежнему, распадаются на множество несвязанных полей.

Пример:

Вместо работы с объектом как с единым целым, нам опять приходится работать со множеством полей:

            doSomething(leaders [lastName][lenin], leaders [firstName][lenin], leaders [surName][lenin]);
          

Во-вторых, обращение к вложенным данным происходит «задом-наперёд».

Пример:

Запись

            leaders [propertyNumber][peopleNumber]
          

означает не человека peopleNumber хранящего свойство propertyNumber, а, наоборот, свойство, propertyNumber хранящее внутри себя человека!

Использовать красивые приёмы работы с данными не так сложно.

Вместо параллельных массивов можно даже воспользоваться предыдущим приёмом с многомерными массивами, просто переставив индексы местами, так чтобы: сначала шёл номер записи, а затем — номер свойства.

Пример:
            char *leaders [7][3] = 
              {
                {"Ленин",    "Владимир",   "Ильич"},
                {"Сталин",   "Иосиф",      "Виссарионович"},
                {"Хрущёв",   "Никита",     "Сергеевич"},
                {"Брежнев",  "Леонид",     "Ильич"},
                {"Андропов", "Юрий",       "Владимирович"},
                {"Черненко", "Константин", "Устинович"},
                {"Горбачёв", "Михаил",     "Сергеевич"},
              };
            
            const lenin = 0, stalin = 1, brezhnev = 2, gorbachev = 6;
            const lastName = 0, firstName = 1, surName = 2;
            
            
            //Печатаем: "Владимир Ленин"
            cout<<leaders [lenin][firstName]<<" "<< leaders [lenin][lastName];
            
            //Печатаем: "Леонид Брежнев"
            cout<<leaders [brezhnev][firstName]<<" "<< leaders [brezhnev][lastName];
            
            //Печатаем: "Михаил Горбачёв"
            cout<<leaders [gorbachev][firstName]<<" "<<leaders[gorbachev][lastName];
          

Этот способ уже имеет ряд преимуществ перед параллельными массивами.

Во-первых, «свойства» «объекта» объединены в единый контейнер. Мы можем работать с «объектом», как с единым целым.

Пример:

Делаем что-то с Хрущёвым:

            doSomething (leaders [khrushchev]);
          

Во-вторых, обращение к данным идёт в иерархическом порядке.

Пример:

Все советские лидеры: leaders

Лидер — Хрущёв: leaders [khrushchev]

Имя Хрущёва: leaders [khrushchev] [firstName]

Однако, использование многомерных массивов имеет и ряд серьёзных недостатков.

Во-первых, обращение к «свойствам» происходит не через осмысленное имя: leaders[2].firstName, а через номер свойства: leaders[2][1]. Для нормального обращения через осмысленные имена приходится объявлять лишние константы, что тоже достаточно уродливо.

Во-вторых, «объект» не может иметь «свойства» разных типов. Пожалуй, это самый серьёзный недостаток многомерных массивов.

Разумеется, самым правильным и красивым решением является создание массива объектов или структур.

Пример:
            People *leaders [7] = 
              {
              new People ("Ленин",    "Владимир",   "Ильич"),
              new People ("Сталин",   "Иосиф",      "Виссарионович"),
              new People ("Хрущёв",   "Никита",     "Сергеевич"),
              new People ("Брежнев",  "Леонид",     "Ильич"),
              new People ("Андропов", "Юрий",       "Владимирович"),
              new People ("Черненко", "Константин", "Устинович"),
              new People ("Горбачёв", "Михаил",     "Сергеевич")
              };

            //Эти константы – только для удобства чтения примера. В реальном коде их не будет
            const lenin = 0, stalin = 1, brezhnev = 2, gorbachev = 6;


            //Печатаем: "Владимир Ленин"
            cout<<leaders [lenin].firstName<<" "<< leaders [lenin].lastName;

            //Печатаем: "Леонид Брежнев"
            cout<<leaders [brezhnev].firstName<<" "<< leaders [brezhnev].lastName;

            //Печатаем: "Михаил Горбачёв"
            cout<<leaders [gorbachev].firstName<<" "<< leaders [gorbachev].lastName;
          

Обязательное хранение размера массива в отдельной переменной

В двух словах:

Размер массива должен быть доступен через его свойство, а НЕ только из отдельной переменной.

Итак, при работе с вложенными данными следует соблюдать правила иерархии: связанные данные должны иметь общий контейнер; и при обращении к ним следует соблюдать иерархический порядок.

В процедурных языках эти правила нередко нарушаются, причём не только при использовании параллельных массивов.

Ещё одним примером некрасивой работы с данными является обязательное хранение размера массива в отдельной переменной.

Пример:

Предположим, нам надо считать в массив фамилии из текстового файла.

Поскольку число фамилий нам заранее неизвестно, мы объявляем массив names с заведомо большим количеством элементов (например, 1000), а число реально используемых элементов храним в отдельной переменной length.

            var
              //names - массив фамилий с заведомо большим количеством элементов
              names : array [0..1000] of string;
              
              //length - число реально использованных элементов
              length: integer;
                
            begin
              assign (input, 'input.txt'); reset (input); 
              
              {/*
              Считываем данные из файла в массив
              */}
              length := 0;
              while not SeekEof (input) do
                begin
                  length := length + 1;
                  read (names [length]);
                end;
              
            end.
          

При этом, так же, нарушаются все возможные правила работы с иерархичными данными:

Во-первых, массив перестаёт быть единым объектом и распадается на две независимые сущности: собственно данные и размер массива.

Пример:

Вместо работы с массивом как с единым целым, нам приходится передавать его по частям: собственно данные — names и размер — length.

            doSomething (names, length);
          

Во-вторых, нарушается иерархический порядок работы с данными.

 

Размер массива должен быть доступен через его свойство length (или, в крайнем случае, через функцию len (array), как в Python, например).

Благодаря этому:

Во-первых, мы можем работать с массивом как с единым объектом.

Пример:

Делаем что-то с массивом:

            doSomething (names);
          

Во-вторых, обращение к свойству массива идёт в иерархическом порядке.

Пример:

Весь массив: array;

Длина массива: array.length;

 

Разумеется, нет ничего плохого в том, чтобы временно закешировать размер массива в отдельной переменной (например, в целях производительности).

Главное, чтобы размер массива при этом всегда был доступен через свойство и без всяких внешних переменных.

Пример:

Предположим, нам надо написать на JavaScript функцию, суммирующую в цикле элементы массива.

Чтобы в каждой итерации цикла не выполнять достаточно ресурсоёмкое для динамического интерпретируемого языка обращение к свойству length, мы можем сохранить размер массива во временной переменной intLength.

            function summ (arNumbers)
              {
              var intSumm = 0;
              
              //intLength - размер массива, закешированный во временной переменной
              var intLength = arNumbers.length;
              
              for (var i = 0; i < intLength; i++)
                {
                intSumm += arNumbers [i];
                }
              return (intSumm);
              }
          

Однако, при этом, размер массива нам всегда остаётся доступен через свойство length.

И мы всегда можем обойтись без внешней переменной:

            //Передаём массив как единое целое, без отдельной передачи его размера
            var intSumm = summ (arNumbers);
          

Доступ к свойствам объекта через object.getProperty () и object.setProperty (value)

В двух словах:

Для доступа к данным должны использоваться свойства, а НЕ методы или открытые поля.

У полей и методов объектов есть своё чёткое предназначение:

Поля — хранят данные;

Методы — реализуют поведение объекта.

В нормальном коде ясно видно, где идёт работа с данными, а где реализуется логика поведения объекта:

Работа с данными: objObject.property1 = "value1";

Поведение объекта: objObject.doSomething (param1, param2);

Использование методов в качестве акцессора и мутатора поля — уродство.

Во-первых, смешиваются два различных понятия: данные объекта и его поведение.

Нарушается естественная конструкция для доступа к данным через оператор присваивания. Оператор присваивания самой своей сутью подразумевает присваивание.

          objObject.property1 = "value1";

          strValue = objObject.property1;
        

Вызов метода, само использование круглых скобок, подразумевает реализацию поведения объекта.

Во-вторых, чтение и запись свойства реализуется по-разному, что противоречит сути поля.

Пример 1:

При использовании свойств, для доступа к полю, как для чтения, так и для записи мы используем одну конструкцию: objObject.property1

            intA = objObject.property1; //Чтение
            objObject.property1 = intB; //Запись
          

При использовании методов, для чтения и для записи поля используются разные конструкции: objObject.getProperty1 () и objObject.setProperty1 ():

            intA = objObject.getProperty1 (); //Чтение
            objObject.setProperty1 (intB); //Запись
          

К полю не будет возможности применять стандартные операторы работы с данными, такие как ++, += и др.

Пример 2:

Мы хотим увеличить значение свойства на 1.

При использовании свойств мы можем воспользоваться естественным для этого действия оператором инкрементации:

            objObject.property1++;
          

При использовании методов, для выполнения элементарного действия приходится писать такую кашу:

            objObject.setProperty1 (objObject.getProperty1 () + 1);
          

 

Для обращения к защищённым полям объекта как к данным, используются свойства. (Внимание: не «открытые поля», а именно — «свойства», см сноску [4]).

Свойство — это интерфейс для красивого и безопасного доступа к данным объекта [5].

При его использовании вызываются методы доступа к данным (например, для выполнения проверки на правильность записываемых в свойство данных).

Однако, вызов этих методов происходит «прозрачно» для разработчика, что позволяет красиво обращаться к данным: value = object.property и object.property = value.

Пример 3:

Класс Person хранит поле _money, доступ к которому осуществляется через свойство money:

            class Person
              {
              private long _money;
             
              public long money
                {
                get
                  {
                  /*
                  Метод, который «прозрачно» вызывается при чтении свойства
                  */
                  return (_money);
                  }
                set 
                  {
                  /*
                  Метод, который «прозрачно» вызывается при изменении свойства.
                  Например, здесь может быть проверка на валидность данных.
                  */
                  _money = value;
                  }
                }
              }
          

Теперь мы можем нормально работать с данными:

            Person psnBillGates = new Person ();
            lngOldRiches = psnBillGates.money;  //Чтение
            psnBillGates.money  = lngNewRiches; //Запись
            psnBillGates.money += 1000000000;   //Инкрементация
          

Свойства поддерживает большое количество современных языков: Delphi, C#, Python, Ruby и др.

Однако немало языков свойства не поддерживают: C++, Java и даже гибкий и красивый JavaScript [6]

Знаете, есть две вещи, которые обязательно надо добавить в JavaScript. Но это не классы и строготипизированные переменные, как думают многие. Отсутствие классов и строгих типов — это не баг, а фича, дающая JavaScript такую гибкость.

Две возможности, которых действительно не хватает в JavaScript — это перегрузка операторов и поддержка свойств [7].

Использование рекурсии для вычисления факториалов и Чисел Фибоначчи

В двух словах:

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

Здесь, в отличие от предыдущих разделов, я не буду столь категоричен.

Ибо рекурсия, или даже философия рекурсии, штука не такая простая.

И вопрос, когда следует (вернее, когда красиво) применять рекурсию, а когда нет, не столь однозначен.

Ну, в функциональных языках (таких как Lisp или Haskell) всё понятно: рекурсия применяется всегда, когда надо выполнить любые повторяющиеся действия. Там даже сумма элементов массива (там он называется списком) вполне может определяться рекурсивно как сумма первого элемента + сумма оставшейся части. В этих языках такой подход гармонирует с философией языка и, потому, красив.

Пример:

Программа вычисления факториала на функциональном языке Haskell красива,

как в интерационной форме:

            factorial n = product [1..n]
          

…так и в рекурсивной с использованием приёма «Сопоставление с образцом»:

            factorial :: Integer -> Integer
            factorial 0 = 1
            factorial n | n > 0 = n * factorial (n - 1)
          

В императивных же языках всё сложнее.

Мне кажется, что в этих языках смысл рекурсии состоит в разбиении задачи на несколько подобных подзадач более низкого ранга. А тех в свою очередь — на насколько под-подзадач, и так, в геометрической прогрессии, пока мы не дойдём до тривиального случая.

Пример 1:

При рекурсивном обходе дерева, мы разбиваем дерево на несколько поддеревьев (ветвей), каждое из поддеревьев на под-поддеревья, и так, пока не дойдём до листов.

Пример 2:

При вычислении определителя матрицы, мы находим определители нескольких подматриц меньшего порядка (миноры), для нахождения же миноров, мы разбиваем каждую из подматриц на под-подматрицы и т.д. пока не дойдём до матриц 2×2.

Пример 3:

При сортировке массива слиянием мы сортируем несколько (обычно два) подмассивов этого массива. Для сортировки каждого подмассива мы сортируем их под-подмассивы, пока не дойдём до подпод…подмассивов длины 2.

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

 

Когда же задача не требует разбиения на несколько подобных, смысл рекурсии вырождается. И применять её в таких случаях — некрасиво.

Самым вопиющим примером уродского применения рекурсии является её использование при вычислении факториала и чисел Фибоначчи.

Я даже не говорю, что это страшно не эффективно. Я говорю, что вычисление факториала и чисел Фибоначчи — чисто итерационная задача, и рекурсивное её решение — это извращение самого смысла, самой сути рекурсии в императивных языках [8].

Как ни странно, эти задачи часто приводят в учебной литературе, причём в самом начале обучения рекурсии, в качестве первого примера. Быть может, рекурсия считается столь сложным для обучения приёмом, именно из-за того, что её объяснение ведётся на совершенно противоестественных её сути примерах…

Отсутствие именованных параметров функции

В двух словах:

Параметры любой нетривиальной функции должны задаваться по осмысленному имени, а НЕ положению в списке аргументов.

Никто не будет спорить с тем, что имена должны отражать суть переменённых. И что использование имён переменных вроде a0, a1, a2 — не самый понятный и красивый приём.

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

Осмысленные имена должны быть у уникальных переменных, обрабатываемых отдельно.

Пример:

Программа, выводящая имя продукта, его кодовое имя и список глюков:

            println ("Имя продукта: "+ objWinVista.name); //Windows Vista
            println ("Кодовое имя: "+ objWinVista.codename); //Longhorn
            println ("Число глюков: "+ objWinVista.bugsCount); //1 000 000 000 :-)
            println ("Список глюков:");
            for (long numBugNumber = 0; numBugNumber < objWinVista.bugsCount; numBugNumber++)
              {
              println (objWinVista.bugs [numBugNumber]);
              }
          

В данном примере name, codename и bugsCount являются уникальными данными и обрабатываются отдельно, поэтому имеют осмысленные имена.

Каждый же из глюков bugs [i] уникальным не является, поэтому имеет не осмысленное имя, а просто номер.

Параметры функции являются такими же полноценными переменными. Однако при вызове функции мы задаём параметр не по его осмысленному имени, а по положению в списке параметров, т.е. по номеру. Это ещё хуже, чем переменные a0, a1, a2.

Пример:

Вот примеры из официальной документации к Java 2D:

            GradientPaint gp = new GradientPaint (50.0f, 50.0f, Color.blue, 50.0f, 250.0f, Color.green);
          

или

            RotationInterpolator rotator = new RotationInterpolator (
              new Alpha (-1, Alpha.DECREASING_ENABLE, 0, 0, 8000, 0, 0, 0, 0, 0),
              xformGroup, axis, 0.0f, (float)Math.PI*2.0f);
          

Что означают эти параметры: -1, Alpha.DECREASING_ENABLE, 0, 0, 8000, 0, 0, 0, 0, 0?

Есть только два случая, когда можно использовать неименованные параметры функции.

Первый случай, это когда параметров немного (не больше 3), и их предназначение очевидно.

Пример:

Math.pow (2, 5) вряд ли можно интерпретировать иначе как 25. Ну, разве что, как 52 :-)

Второй случай, это когда каждый из параметров не является уникальным, и не имеет собственного предназначения.

Пример:

Функция, суммирующая числа: Math.summ (3, 7, 18, -2, 11, 2.3)

Во всех остальных случаях параметры надо задавать по осмысленным именам.

К сожалению, лишь немногие языки поддерживают именованные параметры функций (я могу вспомнить только динамические Perl, Python и Ruby, может быть есть ещё).

Пример (perl):

Функция перевода текста.

            $strResult = translate
              text       => "Hello, world!",
              from       => $lngEnglish,
              to         => $lngRussian,
              vocabulary => $vcblrGeneral,
              quality    => 10;
          

Что же делать в остальных языках?

В процедурных языках (вроде C или Pascal) проблема вызова функций с большим количеством малопонятных параметров стоит особенно остро.

Для её решения вместо передачи большого числа параметров, можно создать структуру, в которой поля будут соответствовать параметрам функции; затем, обращаясь через поля с осмысленными именами записать в структуру нужные данные; и вызвать функцию, передав ей структуру в качестве параметра.

Пример:
            //rectangle1 – структура для хранения параметров функции
            Rectangle rectangle1;

            //Задаём параметры функции
              rectangle1.x               = 80;     //x
              rectangle1.y               = 25;     //y
              rectangle1.width           = 50;     //ширина
              rectangle1.height          = 75;     //высота
              rectangle1.rotation        = 30;     //угол наклона
              rectangle1.borderWeight    = 2;      //толщина контура
              rectangle1.borderColor     = "red";  //цвет контура
              rectangle1.backgroundColor = "blue"; //цвет заливки
              rectangle1.alpha           = 20;     //процент прозрачности

            //Вызываем функцию, передавая ей структуру с параметрами
            drawRectangle (rectangle1);
          

Гораздо больше кода, но зато более понятно и красиво. Хотя, объявление лишних структур для каждой функции, тоже не очень красивое решение.

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

В классических объектно-ориентированных языках вместо сложной функции, лучше всего реализовать шаблон проектирования «Command»: создать объект; затем, обращаясь через свойства с осмысленными именами, записать в него данные; и вызвать метод apply ();

Пример:
            Rectangle rectangle1 = new Rectangle ();
              rectangle1.x               = 80;
              rectangle1.y               = 25;
              rectangle1.width           = 50;
              rectangle1.height          = 75;
              rectangle1.rotation        = 30;
              rectangle1.borderWeight    = 2;
              rectangle1.borderColor     = "red";
              rectangle1.backgroundColor = "blue";
              rectangle1.alpha           = 20;
            rectangle1.draw ();
          

Опять же, гораздо больше кода, но зато понятно, и достаточно красиво.

И, наконец, в динамических языках, не поддерживающих именованные параметры (например JavaScript), в качестве параметра функции можно передать созданный на лету объект с осмысленными свойствами.

Пример:

Функция анимации из библиотеки Dojo Toolkit. В качестве аргумента функции передаём объект со свойствами-аргументами функции:

            var slideLeft = dojo.fx.slideTo
              ({
               node:     divAnim,
               duration: 1000,
               left:     0,
               top:      80
              });
          
Пример:

Функция поиска файлов. Объект с аргументами имеет сложную структуру:

            var arSerchResult = searchFiles
              ({
               text:       "Пушкин",
               extensions: ["txt", "rtf", "doc", "pdf", "odt"],
               hidden:     true,
               modified:
                 {
                 from: new Date (01, 02, 2008),
                 to:   new Date (15, 03, 2008)
                 },
               size:
                 {
                 min: 10000,
                 max: 1000000
                 }
              });
          

Лаконично, понятно и красиво!

Заключение

Пока всё на этом.

Наверняка, в некоторых местах вы будете со мной несогласны — ведь чувство красоты у всех разное.

Ну и не стоит забывать, что отсутствие в коде приведённых «уродских приёмов» — лишь идеальная ситуация, к которой надо стремиться, но приходится жертвовать в определённых ситуациях (например, в целях производительности). Ведь умение приносить жертвы при решении практических задач — один из элементов профессионального программирования.

Примечания

  1. Стив Макконнелл ещё более категоричен, чем я. В книге «Совершенный код» он пишет:

    В идеальном случае сразу объявляйте и определяйте каждую переменную непосредственно перед первым обращением к ней

  2. Вообще, надо стараться избегать длинных функций и методов. Одно из правил рефакторинга: «если текст метода не умещается на экране без прокрутки — это уже повод разбить его на несколько более коротких методов».

    Однако, это далеко не всегда удаётся, например при генерации отчётов или при реализации сложных вычислений.

  3. Есть и противоположенная точка зрения. Например, Ховик Меликян в статье «Клиника плохого кода» пишет, что возврат корней квадратного уравнения через параметр функции: num_roots = qe_solve(10, 20, 2, &x1, &x2); — гораздо красивее, чем использование объектов.

  4. Не надо путать методы, открытые поля и свойства (как, например, в этом самоуверенном комментарии).

    Открытое поле — это просто переменная внутри объекта, доступ к которой извне ничем не ограничен.

    При использовании открытых полей нет никакой возможности отследить обращение к ним, или провести проверку корректности записываемых в поле данных.

    Поэтому, использование открытых полей — нежелательно.

    Для контроля обращения к данным можно использовать методы object.getProperty() и object.setProperty(value).

    Методы позволяют отслеживать обращение к данным, выполнять при этом сопутствующие действия и проверять правильность введённых данных.

    Однако, использование методов — очень некрасиво, о чём я и пишу в статье.

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

    Вместо открытых полей и методов, при наличие такой возможности, следует использовать свойства.

    Свойства — это интерфейс для доступа к данным, совмещающий гибкость и безопасность методов с красотой открытых полей.

    При обращении к свойствам вызываются всё те же методы, однако вызов их происходит «прозрачно» для разработчика.

    Это позволяет красиво обращаться к данным: value = object.property и object.property = value. Как в этом примере с классом Person и свойством money .

  5. Разумеется, свойствами, как и любой другой возможностью, не стоит злоупотреблять, применяя их где только можно.

    Свойства следует использовать для реализации доступа к данным объекта. Ведь использование свойств, само использование оператора присваивания подразумевает доступ к данным.

    Если же, при обращении к данным происходят сильные побочные действия — использовать свойства нежелательно.

    В этом случае, красиво и правильно, как раз, использовать методы. Ведь вызов метода, само наличие круглых скобок предполагает реализацию поведения объекта. О чём я и писал в самом начале этой главы.

  6. Формально поддержка свойств появилась ещё в JavaScript 1.5:

                  object.__defineGetter__ ("property", function ()      {/*Код аксессора*/})
                  object.__defineSetter__ ("property", function (value) {/*Код мутатора*/})
                

    Однако она только относительно недавно стала работать в «нормальных браузерах» и, несмотря на все обещания, до сих пор не работает в Internet Explorer.

  7. Перегрузка операторов появится только в JavaScript 2.0.

  8. Для вычисления чисел Фибоначчи использование рекурсии имеет какой-то смысл: всё-таки основное определение этой функции является рекурсивным:

    Fib (n) = Fib (n−1) + Fib (n−2); Fib (0) = 0; Fib (1) = 1

    Однако, наличие же у факториала рекурсивной формы записи:

    n! = n × (n−1)!

    нисколько не приближает нас ни к пониманию смысла рекурсии, ни к пониманию смысла факториала как произведения чисел от 1 до n.

Библиотека подсветки синтаксиса в этой статье основана на «highlight.js» от Ивана Сагалаева.

527 комментариев:

  1. aktuba
    14.05.2009, 16:45

    С первым и вторым пунктом НЕ согласен.

    Объявление переменных в начале логического блока позволяет контролировать их использование и занятость в блоке. Сам пишу на Delphi, а в последнее время все чаще на PHP. Уже пару раз встречал подобное:

    tmp = rand(1, 10);
    // Тут работаем с tmp
    tmp = random_string();
    // Тут работаем с новым tmp
    ...
    tmp = tmp * 1.5;
    

    В том же Delphi такое не реально.

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

    function doSum(aParam1, aParam2: integer; out oResult: integer):boolean;
    
  2. deepshark
    14.05.2009, 17:56

    С пунктом «Доступ к свойствам объекта через object.getProperty () и object.setProperty (value)» не согласен.

    Во-первых, смешиваются два различных понятия: данные объекта и его поведение.

    Представьте себе ситуацию, в какой-либо программе поголовно используется код типа psnBillGates.money = lngNewRiches;

    Раз этак сотню-другую. А потом вдруг при каждом изменении денег у psnBillGates, да и у любого объекта того же класса, потребуется оповестить налоговую службу об изменении денег на счету. Как вы будете поступать в этом случае, к каждой строчке psnBillGates.money = lngNewRiches; будете дописывать оповещение служб. Мне кажется проще использовать метод setMoney(value) и в нём единожды добавить оповещение и налоговой, и антимонопольной службы.

    То есть на изменение данных у объекта должна быть возможность реагировать (то же поведение)! (Да хотя бы проверка на валидность нового значения)

  3. Банкомат
    14.05.2009, 18:12

    Да по сути все верно написано.

    Есть конечно кое какие притензии по поводу 6-го пункта.

    Вот пример обстрактный

    a = array(1,2,3);

    for(i=0, len = a.len; i<len; i++)

    {

    ...

    }

    ну вот как тут можно обойтись без 6-го пункта?

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

    думаю дальше...

  4. pmalyavkin
    14.05.2009, 18:18

    Объявление всех переменных в начале функции — страшное зло.

    Я с этим не согласен, ведь если есть какие-то (логические) блоки в методе значит этот метод можн разбить на совокупность других методов.

    Не в стречал методов с отдельными логическими блоками, которые нельзя разбить на несколько методов.

  5. pmalyavkin
    14.05.2009, 18:19

    А функции по 200 строк - ....

  6. pmalyavkin
    14.05.2009, 18:29

    >Использование методов в качестве акцессора и мутатора поля — уродство.

    А если нужно какуюто валидацию делать? В свойстве это не уродство?

  7. Mad
    14.05.2009, 18:36

    Cheatsheet на основе этого можно было бы сделать красивый.

    Но, к сожалению, универсальных coding guidelines не бывает.

  8. catap
    14.05.2009, 18:38

    А давно в lisp нельзя писать последовательно инструкции?

    а что делать с do нотацией в haskell?

  9. red_mould
    14.05.2009, 18:51

    Чувак в общем. По порядочку.

    "Переменные должны объявляться в начале логического блока, в котором они используются, а НЕ в начале функции или программы."

    Тут кому как удобно... Тут сильно спорить не буду.

    "Функция должна возвращать результат, зависящий от ее параметров, а НЕ принимать результат в качестве аргумента."

    Ничего она не должна. Смотри сюда. Есть вектор который надо наполнить внутри ф-и... Т.е. легче сделать так

    int foo(std::vector<int> &vec1)

    {

    //сбор вектора.

    }

    main

    {

    std::vector<int> vec;

    foo(vec);

    //тут уже плностью готовый вектор. И нет затрат на сборку конструирование, копирование и разрушение вектора. И т.д.

    }

    "Отсутствие локальных функций"

    Как по мне так полный бред... В с++ есть отдельные блоки, но ты первый в них запутаешься... Если они у тя будут по 20 а то и больше строк..

    "Отсутствие else if"

    Тут все зависит от ситуации...

    "Для доступа к данным должны использоваться свойства, а НЕ методы."

    Круто! По ООПшному! Слов нет, и что такое инукапсуляция тоже никто не задумывается.. Да бес с ней! Любой объект и не только меняет проперти этого обьекта. Или иными словами меняют проперти все кому не лень.

    "Параметры любой нетривиальной функции должны задаваться по осмысленному имени, а НЕ положению в списке аргументов."

    Эээ, полный бред... У функции есть набор параметров такой какой считает нужным автор ф-и... И это полный бред... Извини...

    З.Ы. Я не знаю может ты и мнишь из себя крутого программера, но почитай мат часть... Поможет... Про массивы и числа фибоначи просто умолчу, хотя и про это есть что сказать... Но лень.. Так шо книги почитай а потом в сеть пихай... И еще не отправляй это на rsdn. Засмеют...

  10. Michael
    14.05.2009, 19:15

    deepshark, а что мешает добавить оповещение в блок set? :)

  11. artyfarty
    14.05.2009, 20:06
    То есть на изменение данных у объекта должна быть возможность реагировать (то же поведение)! (Да хотя бы проверка на валидность нового значения)

    Вы путаете поля и свойства. Свойство (property) в современных языках — это геттер и сеттер, маскируемые под обычное поле. А снаружи всё прозрачно.

  12. artyfarty
    14.05.2009, 20:13

    За статью спасибо. Интересно и качественно написано. В большинстве вещей с вами согласен.

    Именованные параметры кажется есть ещё в Groovy, если не путаю ничего, ибо знакомился поверхностно и с удовольствием забыл.

    Никогда кстати не задумывался насчёт ненужности рекурсии в некоторых ситуациях. Хотя вроде и не злоупотреблял.

  13. funfun
    14.05.2009, 21:30

    Спасибо за статью

    Можно поставь якаря для главного списка ( чисто для новых читателей )

  14. Ilya
    14.05.2009, 21:50

    Представьте себе ситуацию, в какой-либо программе поголовно используется код типа psnBillGates.money = lngNewRiches;

    Раз этак сотню-другую. А потом вдруг при каждом изменении денег у psnBillGates, да и у любого объекта того же класса, потребуется оповестить налоговую службу об изменении денег на счету. Как вы будете поступать в этом случае, к каждой строчке psnBillGates.money = lngNewRiches; будете дописывать оповещение служб. Мне кажется проще использовать метод setMoney(value) и в нём единожды добавить оповещение и налоговой, и антимонопольной службы.

    То есть на изменение данных у объекта должна быть возможность реагировать (то же поведение)! (Да хотя бы проверка на валидность нового значения)

    Ну так просто в свойство добавляеться оповещение. Свойства - это и есть объединенный set и get. Просто они позвляют получать нормальный доступ с применением операторо.

  15. Static_Q
    15.05.2009, 00:37

    Спасибо за отличную статью. Некоторая часть подобных мыслей самому приходила в голову.

  16. alekseiko
    15.05.2009, 01:43

    За статью огромное спасибо!!!

    Полностью согласен со всеми пунктами.

    Я сматрю многим не понравилось работа с методами через getProperty(),setProperty(value), кто-то даже про инкапсуляцию говарил и про опавещение кого-то там, друзья советую вам взглянуть как это сделано в C#, акцессоры и мутаторы никуда не диваються!!!

    Мы просто преобритаем удобный нэмспейс и плюсы использования операторов с данными свойствами класса, отсюда красоту написания кода.

    Очень надеюсь что будет продолжение. Так как для новичка это статья будет очень интересна.

    Об искустве программирования можно многое что написать ;-).

    СПАСИБО ещё раз!!!

  17. Melis
    15.05.2009, 08:28

    к Автору.

    Во многом согласен. Кроме вот этих пунктов:

    Первое:

    • 1. Объявление всех переменных в начале программы;
    • 10. Невозможность объявления объектов «на лету».

    Это говорит только о том, что Вы пишите не думая вот и все. Переменные объявленные в начале программы (точнее в начале каждой подпрограммы, если быть точным) делают код однозначным, заставляют не писать спагетти-код (длиной более одного экрана). И еще Если Переменная нужна только один раз, то в 80% случаев без нее можно обойтись! А иначе код становится трудно-читаемым!

    Далее по тексту:

    4. Отсутствие else if;

    else if - первый шажок к нечитаемому коду. Замена - синтаксис case (swich в других языках): во-первых, он читаемее, во-вторых, чаще всего работает быстрее, так как нет лишних проверок.

    Пункты с которыми согласен лишь отчасти:

    6. Хранение размера массива в отдельной переменной;

    Иногда (когда речь идет о действительно больших массивах) затраты на много кратное вычисление длины массива не оправданы, и проще сохранить длину массива в отдельном месте.

    9. Отсутствие именованных параметров функции;

    Крайне спорно. При написании кода

    x=func_name(param1:lala,param2:lala2);

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

  18. deepshark
    15.05.2009, 09:47

    Michael, artyfarty, Ilya, спасибо, был невнимателен, смотрел узко.

    Алик Кириллович, спасибо за статью и дискуссию.

  19. Professor
    15.05.2009, 15:00

    Статья отличная, спасибо.

    Возражу по поводу чисел фибоначчи: не взирая на то, что их определение рекурсивно, рассчитывать их рекурсивно - очень большая ошибка, ведь F(n) = F(n - 1) + F(n - 2) =

    (F(n - 2) + F(n - 3)) + F(n - 2) - тоесть у нас уже на втором шаге два независимых вызова F(n - 2), каждый из которых в свою очередь вызовет F(n - 3) и F(n - 4). Таким образом мы получим лавинную реакцию, которая съест процессор при маленьких n, а при сравнительно небольших (~50-60) стает уже неподъемной. Для сравнения - итерационный алгоритм линейный, и скорее упирается в длину целого числа.

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

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

  20. qnilst
    23.05.2009, 13:05

    Попытаюсь тоже пройтись по порядку:

    1). пункт - не согласен точнее согласен лишь отчасти, в случае если пишется функция, то место под неё в стеке всё равно выделяется сразу под все локальные переменные. Если переменные стоят в начале, то сразу видно, что и как используется функцией. Если они граммотно прокомментированы, то проблем вобще не возникает. Про "поменять местами 2 переменные" - фунции рефакторинга в IDE придумали трусы?

    Смысл выделать переменные есть если использовать блоки {} в C подобных языках. Но почему бы в таких случаях не использовать вложенную функцию.

    2). возврат функции через результат точно нужен в функциональных языках программирования там без этого никуда :). В остальных же опять возникают вопросы иногда это действительно удобно иногда нет, например вы возвращаем результат + код ошибки(или даже список ворнингов, чтобы не было соблазна исключение кидать), тогда тут надо делать объект обёртку, что не всегда удобно особенно в языках типа C/C++. В языках где объекты делаются на лету, конечно большой проблемы не стоит.

    Про матрицы был приведён ужасный пример на C. Вы создаёте объект внутри функции в локальной переменной, не подскажете, а что происходит с локальными переменными после возврата из функции? Правильно они освобождаются, а у Вас радостно передаётся ссылка на переменную "зомби", (в Яве,C# и проч языках со сборщиками мусора подобной проблемы нет, но в C/C++/Pascal надо бы об этом помнить).

    3). Круто, тут ничего не скажешь :) жаль не во всех языках это реализуемо. Ну и наверное если локальная функция потом может использоваться в разных функциях, то "привет refactoring".

    4). Пример хороший, по в Paskal варианты "if ( cond1) and (cond2) then" не равнозначен варианту "if (cond1) then if (cond2) then", т.к. паскаль в первом случае не прервёт проверку после проверки cond1. Вобще в этом вопросе всё сильно зависит от языка и компилятора.

    Написавшему, что else if это замена switch просьба вспомнить, что в switch есть магическая команда break; и код типа switch(a) { case 1: do1; case 2: do2;break; } очень неудобно переписывается через else if. А if (cond1 && cond2){} else if (cond3) {} никак не пишутся через switch.

    5). статья правильна во всех случаях когда не нужна сверхскорость. на опыте (паскаля) паралельные массивы просто быстрее (порядок уже сказать не могу давно было)

    7). доступ к fields через properties. (огорчило не знаение участниками дискуссии, того что такое property). Тут вопрос опять же спорный. В принципе property это очень круто, если язык позволяет использовать разные уровни доступа. т.е. private setField; public getField; /паскаль не позволяет, в java только в следующей версии появятся свойства/, в этом случае пропертями не обойтись

    8). согласен с автором. В не функциональных языках действительно лучше не использовать рекурсию там, где это возможно. Но надо вспомнить о том, что можно сохранять результат вычисления фунции в зависимости от поданных значений. Причём в c (с gcc точно) компилятор может сам позаботиться об этом - в таком случае можно получить прибавку в скорости (за счет памяти)

    9). да человеку, которому лень изучать Ваши интерфейсы так будет удобно. Так же это удобно, когда можно передавать не все параметры из большого кол-ва, тогда не надо писать тысячи перегруженных функций (особенно в пхп где перегрузки нет (не уверен на счёт пхп5). Но хорошо бы подумать за счёт чего появляется это удобство и как работает такой подход :). Может получиться так, что потери слишком большие. Мне понравился вариант в python где функция задаётся как def name(a,b,c,k*,k**): где k* это список именованных параметров k** просто список параметров по номеру (пинайте больно если перепутал порядок), но общий смысл тот, что там обработаны все возможности: передача с заданным порядком, именованные параметры, передача неописанных именованных параметров, передача списка неименованных параметров.

    10). возможность создания объектов это круто конечно. Но опять же нужно думать какие у этих объектов могут быть возможности и что будет стоять за этим созданием объектов. В общем в языках с использованием статистического /не путать со static/ связывания мы его уже не получим.

    Все могу слова не претендуют на оригинальность или правильность.

    Как говорит препод по информатике: "В программировании всегда приводятся противоположные рекомендации. Поэтому умение программировать заключается в том, чтобы выбирать среди рекомендаций правильный баланс. Следование любому набору рекомендаций доведённому до абсурда приведёт к тому, что программа будет нечитаемой, неподдерживаемой и нестабильной".

    С Уважением.

  21. Владимир
    26.05.2009, 08:23

    Не согласен по поводу локальных функций.

    Свое не согласия вырожу только одним вопросом:

    При повторном использовании локальной функции в другой функции ее что придется искать(а я понял автор очень сильно не нравиться ходить по коду) и копировать или забить на поиски и плодить код, не хорошо это...

    И по свойствам, да в тех языках где поддерживается синтаксис и использование понятия свойство не нужно плодить методы, но по-моему в C\C++ без функций не обойтись, ведь данные объекта(класса) должны храниться отдельно, а любые действия над ними оформляются функциями. Один из принципов ООП (инкапсуляция).

    И еще примеры с факториалом и числами Фибоначчи, правильно написано приводятся в учебниках как пример, так как легче объяснить что значит рекурсия. Рекурсия сложное понятие, и не многим она дается с первого раза, да после обучения нужно писать более организованный код, но это уже остается на совести пользователя.

    Спасибо за статью, полезно прочитать.

  22. phpdude
    27.05.2009, 17:51

    автор. респект!

    сам думаю 100% также.

    АХРЕНЕННО.

    Последнее время начинаю думать, почему все языки не есть яваскрипт + c# ? И тогда не пришлось бы плодить адское колво 1 разовых языков

  23. Grass
    07.06.2009, 22:16

    @Melis

    9. Отсутствие именованных параметров функции;

    Крайне спорно. При написании кода

    x=func_name(param1:lala,param2:lala2);
    

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

    Жонглирование порядком? Насколько я понимаю, список аргументов предстает ассоциативным массивом.

  24. Павел
    12.06.2009, 15:43

    Статья интересная. Но мне(да и не только мне) было бы интереснее, если бы пример кода был бы на двух языках. К примеру на вашем(я так его и неопределил) и на питоне к примеру

  25. dizelbox
    13.06.2009, 00:09

    Все правильно сказано, я сам программист, и придерживаюсь точно таких же принципов.

  26. Serg
    13.06.2009, 05:48

    Статья имеет огромное значение для начинающих программистов, вроде меня...

  27. Инквизитор
    17.06.2009, 18:15

    Сжечь еретика! У каждого своё понятие красоты, не надо приводить аксиомы, забивая молодежи головы больными стереотипами...

  28. qnikst
    06.07.2009, 09:41

    @phpdude

    Последнее время начинаю думать, почему все языки не есть яваскрипт + c# ? И тогда не пришлось бы плодить адское колво 1 разовых языков

    Вы имеете ввиду asm, c, bash,java, pascal etc.?

    Почти все советы спорные и даже очень.

  29. Максим
    20.07.2009, 00:21

    А для кого стараться? Для взломщиков? Ага! Чтобы им код понимать легче было! Каждый программирует так, как ему легче и понятнее.

  30. Олег
    25.07.2009, 13:23

    Здрасте!

    Первый же приём...

    А вам не кажется, что если класс или метод можно разбить на логичесмкие блоки, то лучше было бы разбить сам класс или метод на несколько отдельных классов/методов?

    И сразу же приводите пример огромного метода, который можно было бы разбить на 5 нормальных и у которых объявление всех локальных переменных начинается в начале метода. :)

    З.Ы.: А на картинке что? Неужели мне не привиделось и вы объявляете стопку переменных в одной строке, через запятую? И кто говорит о чистоте кода?

  31. Олег
    25.07.2009, 13:29
    var intLength,
          elTemp,
          intCenterIndex,
          intLeftSubarrayLength,
          intRightSubarrayLength,
          arSortedSubarray,
          intLeftElIndex,
          intRihtElIndex,
          i;
    

    Вы коллекционируете самые плохие практики программирования?

    Вы только представьте: У нас есть функция в 300 строк кода [2].

    Вот где зло и о чём надо было писать, а не о постановке переменных.

  32. Олег
    25.07.2009, 13:54

    Извините, что сразу такие комментарии. Просто сразу, первое же и задело. Видел я такой код, в нём прривлекательности ровно нуль. А, вообще, очень достойная попытка описать что-нибудь - очень добротно и многословно, прям разжевали и в рот положили.

    Я не думаю что JavaScript именно тот язык программирования, который нужно приводить в пример в статье о "красоте программного кода".

    Возврат результата функции через её параметр - очень нужная и важная штука.

    Локальные функции лучше вообще вынести в отдельный контекст/класс *Context.

    В общем-то это всё моё ИМНО.

  33. Алексей
    27.07.2009, 18:53

    Я раньше загонялся красотой кода, структурой и т.д. Но после того как на меня наехал препод по кодингу за то, что я использую не рациональный подход, предусмотрев слишком много лишних вариантов и код получился у меня не понятный(хотя его оптимизация заняла раз в 10 больше времени разработки),я забил.

    Переменные не выношу, все должно быть к месту...

  34. dr.Beep
    03.08.2009, 14:17

    Совершая нападки на аксессоры, ты плюешь против ветра. Много ли серьезных книжек ты прочел, и, что самое главное, много ли серьезных проектов поднял и сопровождал ?..

  35. Tena
    21.08.2009, 19:09

    Да ваще какая разница какой код главное результат!

  36. Snowcore
    04.09.2009, 15:41

    @Tena: ну не скажите... Красота кода - это очень важно!

    А по поводу использования параллельных массивов - многие их используют в парсерах. Когда приходится при помощи регулярных выражений вытаскивать определенные значения.

  37. Daniil Baturin
    10.09.2009, 04:47

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

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

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

    Про именованные параметры можно добавить о существующих в Python (может и где-то еще, не в курсе) значениях параметров по умолчанию, позволяющих не перегружать методы и создавать логичное дефолтное поведение.

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

  38. Dioniisiya
    10.09.2009, 15:32

    Спасибо за статью

    Можно поставь якаря для главного списка ( чисто для новых читателей )

  39. валенсия
    02.11.2009, 22:08

    Да уж...не знал,что многие эти приемы настолько смертельны для программы...огромное спасибо автору!=)

  40. Андрей
    04.11.2009, 14:14

    Все считаю по теме, широко написано

  41. Gozar
    26.11.2009, 22:09

    Статья конечно неоднозначная, по крайней мере для меня. Все языки меня мало волнуют, а вот применимо к javascript интересно. Обзор стилей написания заставил проанализировать собственную технику письма. Считаю так, если логично применять тот или иной способ, то его нужно применять. Не всегда удается продумать все наперед, для этого нужен определенный опыт проектирования систем. К примеру нет смысла делать функцию локальной если ее функционал будет использоваться в дальнейшем и это сразу закладывается на будущее, с другой стороны нет смысла плодить такие функции в массовом количестве. Мне кажется здесь важно понимать такую грань, а не делать или не делать как написано в этих "10 правилах". Однако подведу черту, статья безусловно заставляет задуматься над тем что используешь в данный момент. Побольше бы таких статей.

  42. дима
    01.12.2009, 00:10

    подскажите что делать если реально устаешь от кодинга?

  43. Константин
    14.12.2009, 04:20

    Сначала критика:

    1)

    Вы только представьте: У нас есть функция в 300 строк кода

    такую функцию стоит добавить в признаки уродского кода ;)

    2)

    Отсутствие else if

    switch / case, и будет вам счастье.

    3)

    Написавшему, что else if это замена switch просьба вспомнить, что в switch есть магическая команда break; и код типа switch (a) { case 1: do1; case 2: do2;break; } очень неудобно переписывается через else if. А if (cond1 && cond2){} else if (cond3) {} никак не пишутся через switch.

    switch (true) { ... } и пишется всё, что угодно.

    4)

    Обязательное хранение размера массива в отдельной переменной

    смотря какой размер массива, правда, автор сам уже уточнил:

    Разумеется, нет ничего плохого в том, чтобы временно закешировать размер массива в отдельной переменной (например, в целях производительности).

    5)

    Доступ к свойствам объекта через

    object.getProperty () и object.setProperty (value)

    Плохие примеры... billGates.getProperty('money') - бесспорное уродство. Но вот billGates.money += 100, тоже довольно плохо, потому что при прямой записи у нас нет возможности контролировать валидность данных, и совершать связанные действия.

    Вот неплохая статья по теме, если интересно - читайте:

    http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html?page=1

    6)

    Использование рекурсии ... http://www.alik.su/articles/10-ugly-programming-techniques/recursion-to-factorials.png

    Картинка немного радикальная ;) может корректнее было написать "не стоит использовать рекурсию, если вы не понимаете зачем она там".

    7)

    ↑ Перегрузка операторов появится только в JavaScript 2.0.

    Жуть. Надеюсь, ни один нормальный интерпретатор не будет ее поддерживать ... так ни для чего более умного, чем обфусцирование кода, она не нужна.

    П.С.: Хорошо, что есть такие статьи - они заставляют думать :) Автору - спасибо.

  44. BlackApricot
    14.12.2009, 07:41

    Почитал, хм, любопытно, и сделал такие выводы.

    В статье идёт речь о персональной(для каждого отдельно взятого) манере написания кода.

    Утверждать, что писать надо так, и только так, а не иначе, ну это не серьёзно. Все мы люди, и все мы разные.

    Несколько дней назад, мне попалась маленькая заметка, но уж очень яростная, её смысл можно свести к одному предложению:

    "Все козлы, кто пишет не так, как я, мне не удобно читать ваш код"

    И человек приводит пример, как мы должны писать, чтобы ему было хорошо. Написано, всё это было на грани фола.

    А здесь нам предоставили возможность дискутировать, хотя и не вижу о чём.

    На одном из форумов попался вопрос начинающего, как правильно писать код, ну ему и ответили, как тебе удобно так и пиши.

  45. KASъ
    20.01.2010, 16:10

    ух... спс за статью, но можно было бы разбить на несколько ибо не осилил всю

  46. Kein
    01.02.2010, 05:54

    Добавлю и я свое имхо. Много с чем не согласен, но особо...

    Пункт 2.

    Кодил я на ассемблере. А вы?

    Вы в курсе каким образом передается параметр в функцию? Через стэк. А каким образом он возвращается? Тоже через стэк.

    А теперь представим что вы возвращаете через стэк объект на 5мб. А теперь это в цикле на 1000+ итераций в кадр.

    О да! почему у меня все висит! А почему на эту игру не хватает 4гб оперативки? Как такое возможно?!

    Категорический против 7 пункта. Был такой случай что пришлось у объектов отслеживать изменение параметра(что не было изначально запланировано в проекте), что бы запретить в некоторых случаях, а в некоторых модифицировать параметр иначе, чем запрашивается. Что бы вы делали с вашим object.property++ в данном случае?

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

  47. Noisy Wizard
    11.02.2010, 21:57

    Процесс творческий, кто-то любит порядок и красоту, кто-то и в хаосе себя вполне уютно чувствует.

  48. Andrew
    09.03.2010, 20:54

    Беру статью на заметку

    У меня друг программист, думаю ему пригодятся советы

    Спасибо

    5

  49. oleg
    11.03.2010, 21:50

    Классная статья! Некоторые моменты приходили и мне в голову. А вам +1 подписчик:)

  50. shvedsky
    25.03.2010, 00:04

    А Вы не заметили, что Вы своими пунктами как идуальный, фактически, описываете функциональный язык программирования?

  51. Андрей
    25.03.2010, 00:40

    Неплохие советы начинающим, а так очень много спорных моментов, особенно если идёт речь об оптимизации на скорость работы.

  52. Holiday
    25.03.2010, 02:05

    Интересный пост - лично я в своих проектах тоже как-то по началу думал так же ,но потом как-то разленился, так что грустно как-то...Спасибо за единомыслие!

  53. Ковалевский Андрей
    25.03.2010, 15:02

    Стремление к красоте кода - очень-очень похвальное поведение, но уверен, что правила должны быть у каждого свои. Могу привести контрпример ко второму пункту, где при описанном подходе не только потеряется эффективность, но и красота:

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

    var object;
    
    if (function_1(&object) &&
        function_2(&object) &&
        function_3(&object) &&
        function_4(&object) &&
        function_5(&object)
       ) {
        ...
    }
    
    
  54. paganproger
    26.03.2010, 05:08

    Читать было интересно, но есть очень спорные моменты, где каждому своё.

  55. Тимур
    27.03.2010, 11:30

    1-й пункт высосан из пальца.

    Вопрос возникает, что делать, если разрабатываешь на чистом Си? Как эта теория сработает? Заявления о том, что язык Си фигня и прочее - как-то смешно будет выглядеть.

    Да и более верным подходом будет разбить большую мотню кода на более мелкие процедуры

  56. Травиан
    01.04.2010, 16:51

    Как раз изучая программирование возьму на заметку

  57. Медик
    19.04.2010, 20:50

    Я правда только начинаю ПХП постигать, такое громадное количество букав не реально за раз переварить,будем возвращаться

  58. Weblancer
    21.04.2010, 14:28

    По поводу объявления переменных могу сказать то, что кому-то удобно объявить их в начале программы и он это делает на протяжении 10 лет и ему это удобно. Может для Вас после этого переписать этот код будет невозможным заданием, а ему удобно. А в остальном согласен.

  59. Алекс
    14.05.2010, 12:41

    Товарищи!

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

  60. Sngurka
    19.05.2010, 08:06

    Очень полезные советы, раньше некоторые элементы делала не так, теперь благодаря вашему доступному объяснению, буду делать более удобно. Кстати блоки "В двух словах" очень наглядно демонстрируют основную мысль

  61. Bohdanbiz
    22.05.2010, 23:25

    Мне очень понравилась статья! Большое спасибо автору. Сделал для себя пару выводов.. Сейчас изучаю Delphi..

  62. Виктор
    28.05.2010, 12:52

    Вам не кажется что статья длинновата??:)) но я все таки осилил её до конца и пару полезных советов изьял для себя, спасибо

  63. Программер
    29.05.2010, 11:38

    Задумался над вторым пунктом.. О некоторых пунктах вообще раньше не думал. Буду выводить свою систему правил))

  64. Роман
    13.06.2010, 17:42

    Спасибо за интересную статью. Действительно, аккуратный код сейчас очень важною. Даже в егэ по информатике на паскале требует ОПТИМАЛЬНОЕ решение задачи! вот так)

  65. zagovor
    18.06.2010, 18:28

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

  66. Димчик
    20.06.2010, 16:54

    Спасибо за статью, считаю она очень полезна для PHP программистов.Всё по порядку, подробно и понятно. Ваши статьи интересно читать!

  67. Громит
    22.06.2010, 14:13

    Для любого программера это полезно. Прочитав, я задумался о своем стиле коддинга. Почти все уродские приемы я не использую давным давно, но есть один.

    Спасибо за пост. Буду читать дальше ваш блог

    ЗЫ первый мой коммент

  68. Лансер
    01.07.2010, 12:19

    Отсутствие комментариев в коде или комментарии не по делу.

  69. Василий
    12.07.2010, 10:54

    Статья полнейшая лажа.

    Такие вещи в первом семестре объясняют в уважающем себя инженерном ВУЗе.

    Полезно для тех кто не обучается по специальности программиста,т.е. для тех кто до прочтения этой статьи являлся говнокодером.

  70. Dada
    20.07.2010, 18:21

    Помню как нам преподавательница по программированию все вбивала, что программировать надо красиво, с понятной структурой. И действительно потом анализировать программу на ошибки становилось легче и код становился более читаемым.

  71. Семён
    30.07.2010, 17:07

    Самый близкий мне по идеологии язык — Руби. В нём, например, доступ к параметрам осуществляется всегда через методы. В качестве примера, покажу класс, в котором доступ к параметру записывается в лог.

    class ProtectedClient < Client
    
    # Все данные класса содержатся в переменных, начинающихся на @.
    # Они недоступны извне.
    
    def money
      @log.info 'Получен баланс клиента'
      @money # "return" можно опускать
    end
    
    def money=(val) # в названиях методов могут содержаться знаки равно, арифметических операций, а так же восклицательный и вопросительный знак
      @log.info 'Изменён баланс клиента'
      @money = val
    end
    
    end
    
    petr = ProtectedClient.new
    p petr.money # выведет количество денег Пети и запишет это в журнал
    petr.money = 500 # изменит количество денег Пети и запишет это в журнал
    # эквивалентно petr.money=(500)
    
    

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

  72. slashwood
    02.08.2010, 15:39

    Я за 5ть лет обучения научился красиво писать программы, работаю программистом уже несколько лет. А вот когда у жены не приняли задачу на паскале, сделанную мною, по причине большого количества функций(4 функции в программе), я просто офигел, пришлось переписывать все без функций, код увеличился в 2 раза. Потом задачу снова забраковали - переменные слишком длинные, используйте однобуквенные сокращения, сказал препод.

  73. Илья
    03.08.2010, 15:14

    Я уже не первый год работаю разработчиком на Java. Хоть я и завел свой блог, я все еще пишу кое какие программы на Java. Язык передовой, но, конечно минусов он не лишен. Правда этой осенью уже будут выпускать 7ую Джаву. Может в новых версиях будет поддержка свойств.

  74. TiamatInc
    09.08.2010, 17:33

    Прочитал статью, вспомнил как в универе над преподами издевался используя в С++, обращение к массиву в виде номер_элемента[имя-массива], половина преподавателей просто не верило, что это работает.

  75. gdever
    11.08.2010, 14:14

    Статья отличная! Спасибо ) Пошел читать МакКонела.

  76. Blender
    13.08.2010, 11:39

    Хорошая развернутая статья. Некоторые подобные идеи приходили в голову. В большинстве вещей соглашусь. В первую очередь, что код должен быть грамотно и красиво написан, что б хотя бы самому не заблудится в нем :). И после написания другой программер понимал что к чему. Тем более если это большой проект в котором участвуют много народа. Об искусстве программирования можно многое что написать. Жаль не во всех языках реализуемы перечисленные методы.

  77. Andrew
    15.08.2010, 16:12

    Я так понял, что это самый популярный пост

  78. Валенок
    18.09.2010, 18:02

    Когда прочитал про функцию в 300 строк кода - обалдел.

    За последние несколько лет работы, ни один/одна функция/процедура/функ.блок не превысил размерами максимум пару окон редактора.И это не потому что очень простые задачи.

    PS Со всем остальным, вообщем, согласен.

  79. Oleg
    24.09.2010, 12:35

    Код становится в разы лучше, если исповедует какой-то единый стиль. А это уже ложится на плечи разработчика. Увы, разработчики редко берутся нести такую ношу :)

  80. alexey
    21.10.2010, 23:33

    Не всегда код пишется так "как надо", чаще всего "как придется"... из-за нехватки времени.

    Хорошо писать для души... программировать ради программирования, у кого есть такая возможность - счастливые люди :)

  81. Николай
    26.10.2010, 19:17

    Начал читать и, ушел…Ушел куда-то. Вспомнил 80-годы прошлого столетия. Как на своем первом компьютере(самостоятельно собранным, рисовал

    плату, травил и потом паял все) писал на бейсике для своих детей простенькие программки.

    Теперь не те компьютеры, и не те языки программирования

  82. Dmitry
    10.11.2010, 12:10

    Всю статью не осилил, но многие принципы понял. Это все со временем приходит, по-моему. С практикой

  83. Тата
    21.11.2010, 20:37

    Иногда надо так быстро получить результат, что уже не до красоты кода. Хотя если приучмть себя к определенным правилам, то потом даже не бужешь замечать, как красивый код пишется сам собой

  84. victor
    24.11.2010, 14:01

    Я считаю что каждый разработчик должен прочитать книгу

    С. Макконнелла "Совершенный код" - тогда все описанные ошибки вряд ли будут совершаться.

  85. Станислав
    08.01.2011, 18:37

    Не рекомендую для новичков эту статью. Сам занимаюсь программированием 12 лет, знаю более десятка языков. Сразу бросается в глаза, что автор плохо знаком с принципами ООП и современными языками. Вся статья - смесь познаний из области функционального программирования и собственного ИМХО. Соглашусь только с 6,7,8 и 10 пунктами.

    Первый пункт у меня вообще вызвал логическое противоречие, поскольку в заголовке написано одно, а в теле параграфа абсолютно другое. Так писать нельзя.

  86. Russkii
    10.01.2011, 01:49

    Стоящая статья, буду рекомендовать начинающим программерам. А еще, почему больше не пишите? Что случилось?

  87. PavelDev
    14.01.2011, 14:44

    Сам я еще не суперпрофессиональный программист, поэтому на счет ВСЕХ десяти описанных случаем ничего не скажу.

    Но некоторые из них действительно правильны. Только не думаю, что новичками в программировании это будет полезно, так как им (новичкам) можно голову запутать этой статьей.

  88. Игорь
    28.01.2011, 00:24

    Все верно, только это минимальные на мой взгляд требования. Кстати, многие языку страдают от неверного использования глобального адресного пространства (static), но к счастью в javascript нет такого слова.

  89. bitplanet
    01.02.2011, 00:20

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

  90. Макс
    08.02.2011, 17:20

    Статья блеск

    Читал около часа, но ни секундой не жалею.

    Узнал много нового.

    Сохранил некоторые выписки из кодов, пригодятся в ближайшем будущем.

    Так же добавил сайт в закладки нашёл тут много полезного.

    Так же очень понравилась эта статья.

  91. Виталий
    10.02.2011, 22:46

    Хорошая развернутая статья. Некоторые подобные идеи приходили в голову. В большинстве вещей соглашусь. В первую очередь, что код должен быть грамотно и красиво написан, что б хотя бы самому не заблудится в нем :). И после написания другой программер понимал что к чему. Тем более если это большой проект в котором участвуют много народа. Об искусстве программирования можно многое что написать. Жаль не во всех языках реализуемы перечисленные методы.

  92. Agata
    16.02.2011, 01:42

    Я только начала изучать программирование. Первые шаги в С++. Было приятно, что все написано доступным языком; что в голове появилась некая структура по теме и уложилась на полочки. Спасибо-)

  93. Алексей
    17.02.2011, 12:21

    Да, очень полезная инфа, мне как начинающему программисту)

  94. durano
    28.02.2011, 23:03

    Чечстно говоря ствтья получилось слишком длинной, стоило её разбить на несколько частей, тогда прще было читать.

    С большей частью согласен, но с некторыми вещами нет. Критиковать легче поэтому, на ней и остановлюсь:

    • else if, в большинстве случаев прекрасно заменяеться switch case
    • весь код функции должен помещаться на экран, поэтому вполне хорошим стилем будет объявлять все переменные вначале
  95. Студент
    18.03.2011, 13:12

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

  96. Виктор
    23.03.2011, 12:59

    Да, читать конечно много, но интересно, просмотрел свои программы, нашел пару ошибок, спасибо.

  97. Олег
    25.03.2011, 23:37

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

  98. Mihail
    04.04.2011, 12:09

    Объявление всех переменных в начале программы - нас в университете учили по другому)

  99. русский рэпер
    27.04.2011, 16:09

    конечно же я все не прочитал, так как не все понятно. я начинающий программер))) а так гуд

  100. Fame
    29.04.2011, 15:35

    как говорится - Coding is poetry

  101. Марина
    30.04.2011, 00:32

    в Internet Explorer6 JavaScript 2.0. работает нормально, но появляется 9 и все портится.

  102. any4key
    03.05.2011, 14:00

    читал на хабре, занимательно

  103. tapogg
    03.05.2011, 16:13

    отличный материал)

  104. Suh
    04.05.2011, 22:10

    Ох уж эти любители плюсов. Объявление переменных в начале функции было стандартом старого доброго С. Это потом в плюсах стали пихать их где попало.

  105. VadiK
    06.05.2011, 21:49

    Статья - просто золото! Всё так понятно, даже мне, начинающему вебмастеру!

  106. VadiK
    06.05.2011, 21:53

    Когда я развивал свой первый проект(http://fanyou.ucoz.com/publ/5-1-0-35)

  107. DEnWeb
    08.05.2011, 21:55

    Полезный материал, особенно для тех, кто только учится программировать. Лучше с самого начала придерживаться определенных правил написания кода. Есть конечно спорные моменты, но тут каждый для себя сам определяет.

  108. англичанин
    09.05.2011, 01:46

    Замечательный пост. Сижу сейчас и кропотливо анализирую все написанное. Спасибо, одним словом.

  109. Markeloff
    09.05.2011, 15:44

    Cпасибо полезная статья для новичков. Много нового для себя открыл.

  110. Ульяна
    10.05.2011, 15:22

    спасибо за подробное описание. Вы оказали большую помощь новичкам. Конечно просто прочитать мало, я занесла данную страницу в закладки, буду усердно изучать. Спасибо.

  111. Максим
    11.05.2011, 22:03

    благодарность за пост.

    я пока еще в это только вникаю...Надеюсь разберусь.

    На первых порах, когда создавал блог про здоровое питание

    тоже было тяжеловато.

  112. Олег
    13.05.2011, 12:11

    Спасибо за статью. Иногда задумывался сам об этом, но как то не проектировал...

  113. Коля
    13.05.2011, 16:08

    Когда я развивал свой первый проект http://zaknews.at.ua

  114. sickboy
    13.05.2011, 17:16

    Хоть я пока что только начинающий программер, осилил все) Только понял немного не все.

    Спасибо за разжевывание и наглядные картинки, очень полезный материал)

  115. china
    16.05.2011, 11:45

    Статья полезная мне очень помогла, спасибо.

  116. svidovskiy
    17.05.2011, 00:32

    Пост интересный, но к сожилению я ничего пока об етом не понимаю, так как совсем недавно начал учить программирование)

  117. олег
    17.05.2011, 18:38

    Тоже самое, смотрю на это как баран на новые ворота.

  118. Дмитрий
    17.05.2011, 22:11

    Сам использую параллельные массивы, знаю что это не правильно, но так мне удобней и быстрее. Прочитал статью - задумался. Постараюсь переучится.

  119. дер
    18.05.2011, 11:45

    nytujtyj

  120. lagun4ik
    19.05.2011, 19:09

    Прикольно, у меня оказывается множество ошибок =) будем исправляться, а статью в Evernote

  121. дер
    20.05.2011, 10:31

    статья прикольная она мне помогла

  122. Mozgilla
    22.05.2011, 09:59

    Определенно самый лучший пост! Спасибо большое! Вот недавно начала развивать проект http://news-plus.ru/ вроде не плохо получается =)

  123. Tumenbayev
    23.05.2011, 10:05

    Спасибо, за очень такой пышный текст ;) Интересно было почитать, все подробно расписано. Каждый блогер бы так писал, не то что всякие юкозевцы...

  124. rapapam
    23.05.2011, 18:18

    полезная статья

  125. Hedgehog
    23.05.2011, 23:05

    здравствуйте, спасибо конечно за статью, но если честно без обид, я запутался в вашей статье, не мне учить наверно, но оформить немножко по читабельней не помешало бы.

  126. anthonio
    25.05.2011, 09:08

    Думаю, для каждого пункта в каком-нибудь языке и в каком-нибудь случае обязательно найдётся исключение, или, того круче, опровержение.

    Поэтому, я считаю, красота кода не в этих десяти пунктах :)

  127. Константин
    26.05.2011, 11:12

    Вообще програмирование - исскуство, которое не всем дано. Статья конечно же запала в душу....

  128. Texnomob
    27.05.2011, 18:56

    Не ну эта статья просто ваще супер. Да какая подробная всё разжованно класс. Да ещё в таблицах=) Супер автор!

  129. Oleg
    28.05.2011, 17:59

    Да, для новичков статья самое то что нужно.

  130. Игорь
    28.05.2011, 18:01

    Было бы интересновсё прочесть, если бы не так много букв. Просто реально не осилил!

    Можно как-то разбить на несколько частей?

  131. FofonRed
    29.05.2011, 02:31

    блин я до сих пор в ужасе, как можно так много писать?

  132. Юрий
    29.05.2011, 13:10

    На уроках информатики такому не научат :))

  133. Androidik
    29.05.2011, 18:11

    Игорь, читается на одном дыхании.

    Автору за наглядность и подробность +5 молодцом

  134. Денис
    30.05.2011, 14:24

    программа для расчета пошлин на автомобили.

    http://92.50.146.14:70/page3.thm

    предлагаю интеграцию в ваш сервис

    Аська 368254335

  135. Intusrist
    31.05.2011, 13:44

    Сразу вспоминаешь университетский курс С/С++. Автор молодцом!

  136. Alex
    02.06.2011, 11:04

    Бывает такое напишешь, потом пол дня разбираешь что это было.))))))))

  137. Павел
    05.06.2011, 12:16

    да статья навивает ностальгию по инстовскому курсу c++,а сам материал безумно интересен!

  138. originsite
    07.06.2011, 23:02

    C описанием переменных в блоке где они используются - пытался сам с собой бороться, думая что это неверно

  139. Student
    08.06.2011, 12:33

    Спасибо автору, если честно,я тоже парочку таких способов использовал. Но теперь понял, что делал неправильно.

  140. Айонщик
    08.06.2011, 17:13

    Хоть и много букв, но прочитал до конца. Много спорных моментов, но, как говорится, на вкус и цвет товарищей нет.

  141. Пара
    10.06.2011, 08:08

    Sdetkami.ru

  142. Buhjvfy
    10.06.2011, 16:00

    Особенно бесит, когда программеры выпендриваются и делают рекурсию везде, где только можно. Рекурсивные функции намного тяжелей разбирать.

  143. Денис
    12.06.2011, 11:46

    Сильно написал. Статья длинная и подробная. Респект.

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

  144. Roman
    17.06.2011, 05:19

    Только эти 10 парметров влияют на красоту кода?

  145. Mehanik
    18.06.2011, 04:14

    Сууществуют ли еще приему, разрушающие программный код?

  146. Sam
    19.06.2011, 04:16

    Спасибо за подробную статью. Узнал много нового о красоте программного кода. Только вы много пишите. Все в голове не укладывается

  147. Kritik
    20.06.2011, 04:13

    Только эти 10 приемов способны разрушить программный код?

  148. Kritik
    20.06.2011, 04:13

    Только эти 10 приемов способны разрушить программный код?

  149. football
    23.06.2011, 11:59

    Мда, страшная статья, в хорошем смысле этого слова)

    Столько букв, а вообще спасибо, постараюсь прочитать еще раз. Надеюсь больше пойму.

  150. load
    23.06.2011, 18:47

    хороший статья, я вобще тока начал кое как пргграммированием заниматься так что ещё далёк от всего этого)))но всё равно спасибо

  151. anton
    29.06.2011, 11:29

    Мне статья понравилась, но все же трудно усваивается)

  152. mihail
    29.06.2011, 19:35

    faceice.com – Все мы когда-нибудь сталкиваемся с компанией iNetGlobal. Большинство людей хвалят эту компанию, когда другие не понимают, о чем это. Сайт faceice.com ознакомит вас с компанией, расскажет все методы заработка и подробно разъяснит схему заработка в iNetGLobal. Заходите – faceice.com

  153. Максим
    30.06.2011, 01:24

    Вот что значит dofollow блог с неплохими пузомерками, 153 коммента, наверно и статью все 152 человека прочитали :-)

  154. mmxbiz
    30.06.2011, 15:59

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

  155. Владимир
    01.07.2011, 09:06

    Суперская статья, особенно радует объем написанный вами!

  156. serg79
    01.07.2011, 17:15

    <a href="http://www.programulina.com/">Вебмастеру</a>

  157. Сергей
    04.07.2011, 03:03

    Многовато, но многое для себя узнал, как начинающий программист.

  158. Artem777
    04.07.2011, 12:23

    Процесс творческий, кто-то любит порядок и красоту, кто-то и в хаосе себя вполне уютно чувствует.

  159. Juriy
    13.07.2011, 12:18

    Полезная статейка, некоторые пункты учту для себя, ведь нужно учиться граммотно кодить!

  160. Gennady
    14.07.2011, 11:35

    Чем же вам отсутствие else if так не нравится? Зачем его совать там, где не нужно!

  161. Valerij
    14.07.2011, 13:31

    Я тоже некоторые пункты не понимаю! Но может опытному программисту видней!

  162. Vadim
    14.07.2011, 16:42

    Программирование - это целое искусство! А совершенству нет предела, поэтому можно бесконечно совершенствовать свой код!

  163. Profit Hunter
    14.07.2011, 17:51

    Интересная статья, о многом задумался, может немного и сам поменяю стиль!

  164. Arkadiy
    15.07.2011, 13:18

    По-моему, главное, чтобы программ корректно работала, а красота кода - это уже на втором плане!

  165. Roma
    15.07.2011, 14:12

    нас в универе учили что все переменные объявляются в начале программы ))

  166. Anton
    15.07.2011, 16:32

    И зачем все переменные в начале программы, если используются они только в функциях?

  167. Charger
    16.07.2011, 14:08

    Не соглашусь, объявлять переменные нужно в самом начале файла, так уже по переменным можно примерно понять е читая код что и как делает программа.

  168. Mark
    18.07.2011, 00:16

    Великолепный пост, есть над чем задуматься и в чем развиваться создавая новый проект ps: не гнобите ссылки с меня в ответ

  169. Evgeniy
    18.07.2011, 12:43

    с переменными согласен целиком! гораздо удобней объявлять их в блоках где они используются!

  170. Lenka
    19.07.2011, 10:19

    Так сказать, "прописные истины" пишешь )))

  171. Genichesk
    19.07.2011, 11:00

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

  172. Ruslan
    19.07.2011, 11:12

    ну впринципе америку автор не открыл! ))

  173. Andrew
    19.07.2011, 17:20

    По-моему, главное, чтбы программа правльно работала!

  174. mak
    19.07.2011, 18:01

    @Arkadiy Но когда ты смотришь на нее, а тебе от ее не тошнит...тоже не хорошо!!!

    Хотя конечно пускай хорошо работает, а потом можно красоту подогнать!!!

  175. FashionMan
    20.07.2011, 04:45

    Существуют ли еще приемы, способные разрушить программный код?

  176. FashionLady
    20.07.2011, 04:49

    Неслабые приемы, действительно могут взломать систему.

  177. Alexey
    20.07.2011, 16:05

    Очень правильные советы! Если их соблюдать, разобраться в коде будет намного проще!

  178. Danil
    21.07.2011, 16:46

    впринципе Америку не открыл, но и на этом спасибо ))

  179. juicy couture jewelry
    22.07.2011, 05:00

    Зачем его совать там, где не нужно!

  180. gucci on sale
    22.07.2011, 05:06

    в сокращённом виде из-за ограничений на размер материала.

  181. Boris
    22.07.2011, 14:11

    Если бы все следовали таким правилам, разобраться в чужом, да и в своем коде было бы намного проще!

  182. seoeffector
    22.07.2011, 21:23

    Сам принцип понял, да и хорошо и понятно описано так что думаю каждый справится

  183. kokcuk
    26.07.2011, 10:37

    Чтоб я так код писал)

    http://www.flashcollection.net

  184. Роберт
    26.07.2011, 23:59

    Не согласен по поводу локальных функций.

    Свое не согласия вырожу только одним вопросом:

    При повторном использовании локальной функции в другой функции ее что придется искать (а я понял автор очень сильно не нравиться ходить по коду) и копировать или забить на поиски и плодить код, не хорошо это...

    И по свойствам, да в тех языках где поддерживается синтаксис и использование понятия свойство не нужно плодить методы, но по-моему в C\C++ без функций не обойтись, ведь данные объекта (класса) должны храниться отдельно, а любые действия над ними оформляются функциями. Один из принципов ООП (инкапсуляция).

    И еще примеры с факториалом и числами Фибоначчи, правильно написано приводятся в учебниках как пример, так как легче объяснить что значит рекурсия. Рекурсия сложное понятие, и не многим она дается с первого раза, да после обучения нужно писать более организованный код, но это уже остается на совести пользователя.

    Спасибо за статью, полезно прочитать.

  185. mobobob
    27.07.2011, 00:09

    Очень занятно

  186. Алексей
    27.07.2011, 00:45

    Увлекательно, столько нового

  187. Artyom
    27.07.2011, 09:57

    ну это впринципе элементарные правила!

  188. Alisa
    27.07.2011, 13:24

    В университете всегда говорили , что переменные описываются вначале , странно

  189. Dmitriy
    27.07.2011, 15:07

    Никогда не понимал программистов, применяющих объявление всех переменных в начале программы.

  190. Заработок в Интернете
    28.07.2011, 14:20

    Похоже что у автора блога мания на огромные статьи =)

  191. КР
    28.07.2011, 16:56

    СПС

  192. КР
    28.07.2011, 16:57

    СПАСИБО

  193. Timur
    28.07.2011, 17:45

    С некоторыми пунктами категорически не согласен!

  194. Sireja
    28.07.2011, 21:34

    Жалко что у меня нет времени учить языки программирования, пока довольствуюсь HTML и CSS.

  195. Евгений
    29.07.2011, 19:37

    Мега респект автору. Статья очень сильно помогла

  196. Gary
    31.07.2011, 14:22

    Автору +++

    Как раз хтмл изучаю. Очень полезная и простая в понимании статья

  197. Kostik
    02.08.2011, 18:53

    согласен с 1м пунктом! ))

  198. Ростислав
    02.08.2011, 22:11

    Обожаю когда код аккуратный, так он естественно легче воспринимается. Вот когда у вас в комнате бардак, то трудно что-то найти, так и с кодом. Особенно когда пишет код один человек, а переделывает другой, вот тогда и нужен в коде порядок....

  199. Denis
    04.08.2011, 14:12

    Действительно когда код выстроен аккуратно, как то удобнее работать!

  200. Александр
    04.08.2011, 17:30

    Я вот думая лучше по всему этому программированию сделать видео урок как здесь http://1000videourokov.ru/sozdatsayt/phpmysql

  201. Oleg
    04.08.2011, 18:40

    ну нас этим правилам учили изначально!

  202. Роман
    05.08.2011, 13:13

    Хоть, я и давно завязал с программированием (о чем сейчас жалею)- сложно снова напрячь свой мозг. Но статья в целом понравилась. А вы случаем курсы по программированию не ведете?

    Про переменные тут коммент был. Считаю, что переменные надо описывать вначале. Ну и код должен быть хорошо прокомментирован - факт. А то через полгоде без поллитры мозг сломаешь.

  203. Dimon
    05.08.2011, 17:47

    целиком согласен с 1м пунктом!

  204. lexa
    05.08.2011, 19:04

    Очень хорошая статья. Буду пробовать.

  205. gucci handbags on sale
    06.08.2011, 06:45

    Жалко что у меня нет времени учить языки программирования, пока довольствуюсь HTML и CSS.

  206. Анастасия
    06.08.2011, 15:31

    http://razvivashkino.ru/ - Можно заработать. Платим $. Обращаться по асе 736122

  207. Sergey
    08.08.2011, 10:42

    впринципе согласен со всеми пунктами!

  208. Psevdonim
    08.08.2011, 13:11

    А я согласен наоборот со всеми пунктами. В принципе ни чего противоречивого в этом нет вообще.

  209. Egor
    08.08.2011, 19:06

    хорошо написал! всё чётко и понятно!

  210. Ruslan
    10.08.2011, 12:59

    Действительно, когда код структурирован, с ним легче работать!

  211. Google adsense
    11.08.2011, 01:09

    Объявление переменных в начале кода - очень хорошая практика, которая еще с Паскаля нравилась. Зря не используют.

  212. Jordan Air Max shoes
    11.08.2011, 04:47

    Действительно, когда код структурирован, с ним легче работать!

  213. Мудрый кот
    11.08.2011, 09:04

    Очень интересный и объёмный пост.

    Согласен с пользователем: "Google adsense"

    Мне тоже нравится, когда при первом же взгляде на код понимаешь с какими переменными в нём предстоит работать.

  214. Kirill
    11.08.2011, 12:37

    про переменные согласен! очень удобно!

  215. Олег
    11.08.2011, 21:53

    Мега респект автору. Статья очень сильно помогла

    Адский трут было все сюда выложить

  216. Alex
    12.08.2011, 10:27

    1й пункт даже в учебниках по программцине пишут!

  217. Андрей
    12.08.2011, 11:18

    Красиво и аккуратно обычно означает много и громоздко а некоторые оптимизаторы экономят каждый байт :)

  218. Egor
    12.08.2011, 13:40

    та чё громоздко? зато легко найти нужный элемент в случае возникновения ошибки

  219. rusya
    12.08.2011, 14:54

    спасибо,за стптью)с переменными

  220. Kolia
    15.08.2011, 10:25

    хорошие советы, особенно про переменные!

  221. alex
    15.08.2011, 12:01

    Лишь бы программа работала как надо! А красота кода - второстепенное.

  222. Диман
    15.08.2011, 12:57

    Google проводит реформы. Изменений подверглась главная страница сайта и форма поиска. Теперь мы не сможем открыть первую найденную страницу с помощью кнопки "мне повезет". Сама форма поиска теперь будет синего цвета. ec1ef76a19950fe486573788f8966ab5

    Пока данные изменения внедряются в финском Google.

  223. Рустам
    15.08.2011, 22:44

    Неплохо.

  224. Рустам
    15.08.2011, 22:53

    Фильмы на телефон http://tobi-mobi-films.ru/

  225. Сергей
    15.08.2011, 23:04

    Для начала наверное хватит.

  226. Pmnov
    16.08.2011, 12:20
  227. Detective
    17.08.2011, 05:12

    Существуют ли еще приемы, которые разрушают программный код?

  228. Fedor
    17.08.2011, 10:30

    Хорошие советы! Для начинающих программистов самое то!

  229. Valera
    17.08.2011, 14:07

    Абсолютно согласен с 1м пунктом! Как по мне намного удобнее объявлять переменные в нужных блоках!

  230. Кощей
    17.08.2011, 14:27

    Внесу и я свою лепту: Dofollow блог кощея.

    Блин блог засрали коментами, ну раз автор не чистит и блог уже не ведёт, то недолго ему осталось, особенно убивают коменты людей которые типа статью прочитали и умозаключения свои выдвигают, а вот Рустам - красавчик, пишет прямо - "Фильмы на телефон http:/...."

    Всем привет :) Пишите ниже коменты, и получайте кучу тицов.

  231. Spek
    17.08.2011, 16:00

    Хорошая статья!!

  232. gavb
    18.08.2011, 09:21

    <a href="http://pro-anzhi.ru/">трансферы анжи</a>

    <a href="http://pro-anzhi.ru/">фк анжи махачкала</a>

  233. gavb
    18.08.2011, 09:22
  234. Yaroslav
    18.08.2011, 11:42

    для любого квалифицированного программиста это "золотые" правила )))

  235. narsana
    18.08.2011, 12:50

    засрали комменты )) в открытую линки оставляют почистите!!!

  236. Александр
    19.08.2011, 11:53

    Отличная статья!!

  237. Misha
    19.08.2011, 16:45

    Впринципе согласен с автором! Это неотъемлемые правила!

  238. Sasha
    21.08.2011, 19:30

    Очистите спамеров! на кол их

  239. Павел
    21.08.2011, 20:07

    Чистота и порядок кода-действительно искусство, к сожалению многим на этот порядок в коде плевать, придерживаются принципа тяп ляп.

    За статью спасибо.

  240. markus
    22.08.2011, 04:08

    прикольно...

    а вот новый сервис шары ссылки

  241. air max jordan fusions
    22.08.2011, 11:08

    для любого квалифицированного программиста это "золотые" правила )))

  242. Kirill
    22.08.2011, 17:22

    нас преподы по програмщине приучали к порядку в коде!

  243. Tolik
    23.08.2011, 10:45

    согласен с автором! ведь так на много удобнее читать чужой код!

  244. tory burch outlet locations
    23.08.2011, 12:08

    нас преподы по програмщине приучали к порядку в коде!

  245. Denis
    25.08.2011, 18:12

    Действительно хорошие советы по кодингу!

  246. Новости LineAge-2
    25.08.2011, 20:44

    Новости Lineage 2 на http://powerstr1ke.ru

  247. demon
    25.08.2011, 21:38

    онлайн фильмы смотреть

  248. CodFront.Ru
    26.08.2011, 00:15

    Отличная статейка, только большевата читать тяжеловато

  249. tory burch online outlet
    26.08.2011, 12:15

    Отличная статейка, только большевата читать тяжеловато

  250. Вячеслав
    27.08.2011, 18:25

    В большинстве описанных случаев полностью согласен с автором. Код должен быть понятным как до так и после его написания :) ...

  251. Яна
    28.08.2011, 12:34

    Очень занимательная статься. Спасибо, с удовольствием прочитала:)

  252. Александр
    31.08.2011, 00:56

    Вы настоящий художник! Чувствуется, что Вы любите свое дело. Интересно, даже в такой прагматичной вещи, как программирование, можно найти красоту.

  253. Жан Абрамов
    01.09.2011, 20:18

    Эх всегда мечтал обучиться программированию, хотя бы азам, но мозги у меня не те )

  254. toberr
    01.09.2011, 23:58

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

  255. Feel
    03.09.2011, 22:47

    toberr, абсолютно согласен с вами, да и на то, чтобы сделать код красивым, нередко уходит много времени

  256. Freeman
    04.09.2011, 04:00

    Алик, а вы уже начали создавать свой язык программирования?

  257. Alexey
    04.09.2011, 20:43

    По некоторым пунктам категорически не согласен!

  258. Anton
    06.09.2011, 16:41

    Элементарные правила программирования!

  259. Мария
    07.09.2011, 11:40

    absolvo

  260. Мария
    07.09.2011, 11:41

    Очень занимательная статься. Спасибо, с удовольствием прочитала:)

    e512d35c75c50c907d62706a6f5efd88

  261. Alexander
    07.09.2011, 16:50

    советы действительно полезные!

  262. Oleksandr
    08.09.2011, 23:26

    Полезная статья. Объясняются элементарные, но не всегда заметные вещи. В большинстве согласен с автором, но есть некоторые пункты, с которыми не могу согласиться.

    Хранение массива в отдельной переменной все-таки полезно, поскольку наличие такой переменной стимулирует обращаться к ней и, соответственно, обращаться к фиксированному размеру массива.

    Доступ через сеттеры и геттеры: очень полезная штука и она НЕ ДОЛЖНА заменяться прямым доступом к полям, поскольку тогда становиться невозможным оптимизация и проверка данных. Так-же вы не сможете, к примеру, реализовать lazy-initialization, а это очень полезная фича.

    А так, статься полезная, прочитал с удовольствием.

  263. Сергей
    09.09.2011, 10:51

    Люблю, когда код написан красиво. И самому легче потом понимать о чем писал и другим будет удобно.

  264. Alex Restner
    09.09.2011, 10:56

    Полезно, но, как вы правильно сказали - это сугубо личное мнение автора.

  265. Лошадь
    10.09.2011, 21:52

    Привет.

    Сюда

  266. Лошадь
    10.09.2011, 22:10

    <a href="http://prof090.ru">i am</a>

  267. Лошадь
    10.09.2011, 22:12
  268. Андрей
    12.09.2011, 07:09
  269. Kostik
    12.09.2011, 17:44

    всё по делу! красивый код всегда приятно читать!

  270. Rem
    12.09.2011, 21:19

    Есть над чем задуматься. Вы явно не признали бы мой код красивым -)

  271. Rem
    12.09.2011, 21:19

    Есть над чем задуматься. Вы явно не признали бы мой код красивым -)

  272. Vitaliy
    13.09.2011, 17:20

    Это так сказать простые правила программирования )))

  273. Max
    15.09.2011, 17:47

    Возьму себе на заметку пару советов!

  274. damir-tote
    15.09.2011, 18:08

    На блогспоте полно ошибок в кодах, ужас просто.

  275. Marian
    16.09.2011, 11:36

    Да, согласен с автором!

    Код всегда должен быть чистым и понятным, без "уродских приёмов", поскольку не только тому программисту может понадобиться разобраться в коде, который его писал, но и другому, например тестеру.

    Пишите чисто и грамотно! Программирование - это исскуство!

  276. Dans
    16.09.2011, 16:36

    Да уж код надо вычищать до блеска так сказать )

  277. vovasit91
    17.09.2011, 00:19

    Когда прочитал про функцию в 300 строк кода - обалдел.

    За последние несколько лет работы, ни один/одна функция/процедура/функ.блок не превысил размерами максимум пару окон редактора.И это не потому что очень простые задачи.

    PS Со всем остальным, вообщем, согласен.

  278. Salikhoff
    18.09.2011, 12:28

    Обалдел когда прочитал, спасибо, буду переделывать почти все сайты на самописной cms...

  279. longchamp
    18.09.2011, 12:47

    Однако эти блоки — полноценные элементы в иерархии программы. И они тоже имеют право на собственные «локальные» переменные! Которые объявляются в начале этого блока и используются только в его пределах.

  280. Vlad
    18.09.2011, 15:25

    Очень интересная статья, добавлю в закладки.

  281. Artur
    19.09.2011, 12:29

    отличные советы! большое спасибо!

  282. ben
    19.09.2011, 14:28

    соглашусь, программирование - это искусство

  283. ben
    19.09.2011, 14:28

    соглашусь, программирование - это искусство

  284. Николай
    19.09.2011, 14:59

    Статья написана хорошо,автор всё разложил по полочкам.Даже мне понятно,хотя ещё в программировании новичок.

  285. french property sales
    19.09.2011, 21:56

    Ты так здорово! Я не думаю, Ive читал ничего подобного. Так хорошо, чтобы найти кого-нибудь с некоторыми оригинальные мысли по этому вопросу. Спасибо, что начиная с этого вверх. Этот блог является то, что необходимо в Интернете, кто-то с немного оригинальности. Хорошая работа для чего-то нового в Интернете!

  286. Chester
    20.09.2011, 15:47

    Ппц еле осилил, но интересно посмотреть на эти уродские приемы. Пару совпадений нашел )))

  287. megfilth
    20.09.2011, 16:01

    да полный ппц, просто тошнит от таких зрелищь

  288. megfilth
    20.09.2011, 16:06

    а мне все таки как то туговато влезает в мозг )))

  289. megfilth
    20.09.2011, 16:15

    Цените комфорт и истинную красоту? Желаете проводить время в стильной обстановке, элементы которой гармонично сочетаются между собой, но не имеете понятия, как можно этого достичь? Вам сможет помочь профессиональный дизайнер в Саратове в моем лице! Я помогу вам исполнить вашу заветную мечту и создать стильный и удобный интерьер!

  290. Vano
    21.09.2011, 21:47

    С первым пунктом позволю не согласиться

  291. Dima
    22.09.2011, 18:17

    Советы хорошие, для начинающих программистов самое оно!

  292. Vova
    23.09.2011, 11:07

    Советы хорошие))) Ведь всегда удобней оптимизированный код читать)))

  293. nss-perm
    24.09.2011, 00:48

    Гуд Пригоится спс

  294. gucci outlet online
    26.09.2011, 13:46

    Все программные системы иерархичны. Программы делятся на пакеты, пакеты — на классы, классы разбиваются на отдельные функции.

  295. Tory Burch outlet stores
    27.09.2011, 10:32

    Обращение к данным происходит следующим образом

  296. slovn
    28.09.2011, 13:09

    Сам немного программирую. Статья шикарная, добавил в заметки, буду время от времени перечитывать :)

  297. Leonid
    30.09.2011, 14:13

    Возьму на заметку! Особенно 1й пункт!

  298. Смотреть фильмы онлайн бесплатно
    30.09.2011, 17:09

    всё по делу! красивый код всегда приятно читать!

  299. Доктор Кресло
    02.10.2011, 00:37

    мне кажется очень фундоментальный подход к коду - такой подход нужно преподавать в вузах!

  300. Mars
    02.10.2011, 01:24

    вот 1,4,5,8 - полностью согласен, даже бесит

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

  301. Антон
    03.10.2011, 15:17

    Сильно, сильно...

    Достойно трансляции в массы

  302. Знакомства в Украине бесплатно, без регистрации
    03.10.2011, 17:18

    это вынос мозга для меня, набор букв и цифр=)

  303. Anton
    03.10.2011, 17:55

    1й пункт желательно всегда исполнять!

  304. Art Seo
    03.10.2011, 18:55

    Чувак ты реально крут! Нужно своих программеров поучить уму да разуму в написание красивого кода.

    Спасибо за примеры как не нудно делать и как нужно.

    Добавь на сайт кнопку +1 Такое нужно рекомендовать.

  305. Ruslan
    04.10.2011, 17:36

    про переменные абсолбтно согласен!

  306. Doctor
    04.10.2011, 17:51

    Сочетание техники порядка и красоты является истинной составляющей не только программирования, но и бизнеса в целом.

  307. Danil
    06.10.2011, 10:10

    красивый код это хорошо! это может доказать мастерство программиста!

  308. Tor
    06.10.2011, 12:04

    Красивый код это конечно всегда хорошо! Но к сожалению для этого нужно тратить много времени или иметь большой опыт (что сразу получить конечно же не получится), но стремиться к этому я думаю нужно!

  309. Alex
    06.10.2011, 19:05

    Не нужно иметь много опыта что бы в notepad++ поставить табуляцию =) красиво оформленый код будет понятным, не только вам но и др. разработчикам.

  310. Домик
    07.10.2011, 03:35

    А у меня криворукий код получается)))

    Винтовые сваи в Кингисеппе

  311. Kredit für Arbeitslose
    07.10.2011, 13:40

    ну мне до таких познаний ещё очень далеко...

  312. Einrad
    07.10.2011, 13:41

    да ладно, хоршо всё объяснено, мне лично пригодится по работе.

  313. Swatlp102rus
    07.10.2011, 16:13

    Я только начинаю изучать языки программирования, надеюсь ваши советы будут полезны всем программистам :)

  314. shelchckov.yaroslav@yandex.ru
    08.10.2011, 22:07

    shelchckov.yaroslav@yandex.ru

    классный сайт там торренты

  315. shelchckov.yaroslav@yandex.ru
    08.10.2011, 22:09

    http://2011torrents.ucoz.ru/ классный сайт там торренты

  316. Flash
    08.10.2011, 22:39

    с некоторым можно поспорить

  317. Daumensteine
    10.10.2011, 15:22

    конечно можно поспорить. програмирование вещь креативная и у каждого свой подход к решению той или иной задачи

  318. Виталик
    12.10.2011, 12:40

    Для меня нет ничего хуже чем разбиратся в чужом коде!!!

  319. Виталик
    12.10.2011, 12:41

    Другое дело работать с кодом проффесионального программиста

  320. Валерий
    12.10.2011, 21:12

    Да уж код надо вычищать до блеска так сказать )

  321. Катрин
    13.10.2011, 14:53

    Убеждаюсь, что даже в программированиии есть место креативу.

  322. Каменск
    13.10.2011, 16:04

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

  323. Tory Burch outlet
    13.10.2011, 17:10

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

  324. allmanga
    13.10.2011, 22:21

    извините за спам но не хотели бы вы посетить наш сайт allmanga.org

  325. Иван
    15.10.2011, 02:46

    Реально подскажите пожалуйста - а что делать , когда просто устал уже от кода програмного????

  326. Beauty Hair
    16.10.2011, 17:25

    Алик Кириллович, я настаиваю на защите Вами докторской диссертации на данную тему! Блестяще!

    ----------------------------------------------------------

    наращивание волос и химическая завивка

  327. cosmos345
    16.10.2011, 19:21

    Есть что для себя отметить.

  328. Damir
    17.10.2011, 14:32

    ну впринципе ничего нового не увидел!

  329. Busgame
    17.10.2011, 16:13

    Не чего не понятно, но автору спасибо=)

  330. sance
    17.10.2011, 18:34

    Спс за статью, а по теме очень познавательно для новичков!)

  331. Konstantin
    19.10.2011, 16:50

    с первым пунктом абсолютно согласен!

  332. Руслан
    19.10.2011, 23:59

    За статью спасибо. Интересно и качественно написано. В большинстве вещей с вами согласен.

    Именованные параметры кажется есть ещё в Groovy, если не путаю ничего, ибо знакомился поверхностно и с удовольствием забыл.

    Никогда кстати не задумывался насчёт ненужности рекурсии в некоторых ситуациях. Хотя вроде и не злоупотреблял.

  333. Alex
    20.10.2011, 17:31

    интересно было почитать! много подчеркнул для себя!

  334. Tory Burch Outlet
    21.10.2011, 11:03

    я настаиваю на защите Вами докторской диссертации на данную тему! Блестяще!

  335. 23.10.2011, 14:17
  336. Alexander
    23.10.2011, 14:19
  337. Danil
    24.10.2011, 10:41

    Довольно таки граммотно написано!

  338. makeityourring diamond engagement rings
    24.10.2011, 17:32

    Высокий информации. Я действительно удивлен этой темы. Следите за хорошую работу и должность более здесь, чтобы прочитать.

  339. Anton
    24.10.2011, 17:37

    Первый пункт обязателен к исполнению!

  340. Sergey
    25.10.2011, 18:17

    Так сказать, азы программирования!

  341. Misha
    26.10.2011, 17:05

    хорошие советы бля начинающих программистов!

  342. Kirill
    27.10.2011, 17:07

    очень грамматно и актуально написано!

  343. Ivan
    28.10.2011, 13:18

    первый пункт одязателен для исполнения!

  344. Nikita
    28.10.2011, 17:57

    думаю что программеры со стажем всё это и так знают!

  345. Moncler Doudoune
    29.10.2011, 10:16

    Moncler Doudoune кт одязателен для исполнения!

  346. asmoth
    29.10.2011, 21:47

    если пишу для себя, то все равно, в своем коде я не путаюсь

    если для кого-то другого то тут уж все как положено, чистенько с комментами и удобно

  347. Olga
    31.10.2011, 15:47

    Очень полезная статья. Спасибо.

  348. Юлия
    01.11.2011, 12:33

    С некоторыми моментами категорически не согласна, для постороннего человека будет тяжело разобраться например когда "Объявление всех переменных не начале программы" так как учили всю жизнь на оборот. Красота должна быть во всем! =)

  349. shop soccer jerseys
    01.11.2011, 14:39

    Это усложняет комментирование блока: в одном месте мы комментируем переменные, но не знаем, как их использовать; в другом месте мы комментируем алгоритм, но не знаем, с какими данными он работает.

    print ("Добрый вечер!");

    }

  350. Воронов
    02.11.2011, 00:35

    Восхищен таким техническим и подробным обзором

  351. longchamp le pliage
    02.11.2011, 17:26

    if (numHour >= 0 && numHour < 6)

    {

    print ("Спокойной ночи!");

  352. Sergey
    03.11.2011, 11:24

    нас в универе учили что все переменные объявляем в начале программы!

  353. Fedor
    03.11.2011, 12:55

    и нас так же учили, чтобы ничего не забыть!

  354. Александр
    03.11.2011, 15:21

    Хорошие советы не только для начинающих.Но от всех этих кодов порой голова идет кругом.

  355. Сургей
    04.11.2011, 17:51

    Спасибо автору за интересную статью! Очень много полезного для себя подчеркнул!

  356. Slava