Расчет, прежде всего.

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

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

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

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

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

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

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

Так что, нужно всегда выстраивать дерево (сначала желательно на бумаге), потом можно и в голове. Дерево должно выглядеть так – идея N1 (что сломано) + как проверить, идея N2 + как проверить и т.п.. Почему я говорю дерево, да потому, что иногда в не слишком удачно написанных проекта, проверка теории не удается без того, чтобы, например, пофиксить другой баг (для которого тоже нужны записывать варианты). И чем глубже приходятся «копнуть» тем больше шансов потом забыть какой-то из кусочков этого дерева.

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

Ну и вернусь к тому, что я говорил, что метод проверки теории должен быть наибыстрейший. Как по мне, один из самых эффективных метод – комментировать большие куски кода. Это сразу позволяет выявить внутри этого ли модуля находиться баг. Хотя есть и другие не менее эффективные методы.

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

32 комментария to “Расчет, прежде всего.”

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

    • Victor Ronin:

      Да. Логи это вещь.

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

      Единственное, за что я не люблю логи, что они «зашумляют» код.

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

      • я сейчас кажу вещь, за которую меня «расстреляли» в параллельном обсуждении. в Java (да я специалист по «новому Cobol» (с)) есть концепция Aspect Oriented Programming или Аспектно-Ориентированного Программирования. так вот, согласно этой коцепции можно отделить функциональный код программы от служебных функций. в частности аудита, частью которого и является система логирования. я правда пока до конца не разобрался, как эта концепция работает внутри кода (и работает ли вообще) а на уровне пост- и предусловий работает прекрасно. в частности в Spring фрэймворке. как с другими языками я не знаю, потому и пишу в Java. разумеется сама концепция к конкретному языку не привязана.

        • Victor Ronin:

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

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

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

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

          • и еще. кажется я «нащупал» возможности трассировки. идея состоит в том, что (опять таки в Java) 90% функционала это вызовы методов. а вызовы методов можно логировать через пред- и постусловия. т.е. например внутри какого-то метода создается класс Foo, обычно в трэйс-лог кладется before (Trying to create class Foo…), after (Class Foo created: Foo.toString()), trowable (Failed to created class Foo with message: e.getMessage, e.pringStackTrace). так вот, тут три аспекта. никто ведь не мешает создавать аспекты любого уровня абстракции не только для классов нашей бизнесс логики com.mycompany.Foor, com.mycompany.Bar, но и для классов JDK и фрэймворков таких как java.util.Collection, java.sql.Connection и так далее.
            иными словами нужно сместить в мозгу точку зрения на метод. для ООП — метод это единичная и завершенная атомарная конструкция, описывающая некое действие класса. для АОП — метод это лишь набор вызовов других методов, которые в свою очередь вызывают еще методы и так до бесконечности. и уровень ограничения бесконечности и есть уровень трассировки. очень инетерсная идей, действительно революция. в первую очередь в сознании. пойду подумаю еще 🙂 наверное положу к себе в блог статей на эту тему с примерами практической реализации.

            • Victor Ronin:

              Честно говоря я слегка потерялся в комментариях (возможно, потому, что я не большой знаток java).

              Пару вопросов:
              — «так вот, тут три аспекта»

              Что такое аспект вообще в этом АОП?

              Второе, все равно в методе то будет код по логированию (до и после вызова метода). Или есть какая-то языковая конструкция которая позволяет это обойти?

              Я в основном на С/C++ программирую.
              Похоже проблему разделения можно обойти с помощью в лоб обойти с помощью создания «обертки» для каждого метода. Под оберткой я понимаю другой метод, который логирует, вызывает нужный метод и снова логирует.

              Но, таким образом количество методов удваивается. Можно конечно поиграться и накрутить#define, что-бы оно само код нужный в момент компиляции генерило. Но, мне кажется игра не будет стоить свечь.

              • э-ма… собственно про АОП. вобщем-то там все написано и для «плюсов» тоже есть реализация. вот. опять-таки, надеюсь что будет чего написать к себе в блог. ну и открыт для любых дискуссий

                • Victor Ronin:

                  Прочел. Хм… Интересно, очень даже интересно. Как будет обсуждение, я с удовольствием подключусь.

                  Полез читать реализацию для C++.

                  Я просто думаю, что это другой метод срезания программы. Пожалуй если его объединить с ООП должно быть очень мощно.

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

                    • Victor Ronin:

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

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

            • Victor Ronin:

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

              Итак, что мы пытаемся решить

              а) Отделить логирование от функционала.

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

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

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

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

              Скажем, внутри метода, мы ищем что-то в массиве, если находим то пытаемся сделать какую-то операцию. Метод может вернуть, что он завершился неуспешно если мы не нашли в массиве или не смогли сделать операцию.
              Сам метод будет состоять из 3-4 строк, разбивать его на подметоды (как по мне) быссмысленно.

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

              в) По поводу а) и б) мне кажется, это гораздо легче решается именно на уровене IDE. Делается небольшой plugin, который может прятать и показывать код связанный с логгированием. Фактически всегда логирование выглядит примерно так

              A.B(аргументы) или
              A(аргументы)

              Так, что все что нужно будет plugin’у — чтобы программист задал префикс/название функции с помощью которой он логирует.

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

  2. полезная информация…

  3. умение смотреть вперед-хорошее качество

  4. Аноним:

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

  5. twin:

    Большое спасибо давольно таки полезная инфа и коменты

  6. MK:

    Это уже было описано в ТРИЗе, как и многое другое — устройте диверсию в своем коде 🙂

  7. MK:

    теория решения изобретательских задач Альтшуллера. Если вкратце, то это система методов и приемов для решения технических творческих задач, основанных на закономерностях развития технических систем. Но в принципе, их можно использовать практически в любой области, с определенными ограничениями (я, например, сисадмин). У самой теории тоже есть ряд недостатков, но, как мне кажется, с ней есть смысл ознакомиться — может найдете и для себя что-то полезное.

    Собственно линки навскидку (в гугле их должно быть больше):

    http://www.altshuller.ru/
    http://www.trizland.ru/

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

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

  8. Sapiens:

    Лучше всего писать юнит тесты просто. Писать комменты есть антипаттерн. Логировать тоже надо.

    • Victor Ronin:

      Хм… Почему это писать комменты антипаттерн?

      Вчера например я добавил в код строку (строковую константу) которая в переводе с японского значит «quick list», хотя я и примменовал переменную так, что все можно понять. Я все таки позаботился о следующем программисте и добавил комментарий, почему я туда это добавил, почему оно в unicode и как оно должно работать.

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

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

      • Sapiens:

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

        • Victor Ronin:

          > Хороший код должен быть простым и понятным до безобразия.

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

          >а зачем собственно называть вещи в непонятном для другого языке и дописывать >коммент?

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

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

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

          • Sapiens:

            >Я сам пользуюсь таким высказыванием. Но это скорее как идеал к которому >можно тянуться, но добраться нереально.
            Ммм… Ну это не повод взять и отказаться от такой культуры, все равно нужно стремится:)
            По поводу кода с комментами их нужно в любом случае минимизировать, в идеале избавиться от них вообще. Юниты и были рождены для проверки программной логики и если она меняется то и юниты еже с ними естественно)

            • Victor Ronin:

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

              • Sapiens:

                Зачем же так иронизировать?)) Каждому свое в принципе…

                • Victor Ronin:

                  Извиняюсь, занесло.

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

                  • Sapiens:

                    Может быть стоит попробывать ajile методологии чтобы быстро подтянуть всех? Хотя это уже оффтоп. Все извиняюсь умолкаю….

                    • Victor Ronin:

                      Та, все ok.
                      Я собственно говоря, не против оффтопов (кроме того, что явно не относится к IT и бизнесу).

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

                      Просто людям нужен опыт, иногда людям нужен мозг….

                    • Sapiens:

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

                    • Victor Ronin:

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