Replikant_mih
Replikant_mih личный блог
27 мая 2018, 19:37

Кто как дебажит код?

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

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

74 Комментария
  • Дед Нечипор
    27 мая 2018, 20:05
    Дважды вычитываю каждый логически обособленный кусок кода (процедура, функция): первый раз — сразу по окончанию его написания, пока свежа в памяти вся логика и подразумеваемая функциональность, второй — когда заканчиваю работу над основной задачей, частью которой является данный блок — помогает против ошибок, когда скопипастил что-то, но поменял не все что нужно было.
     Иногда практикую первый проход новой задачи делать в режиме пошагового исполнения с контролем значений, но, как правило, предпочитаю внимательно вычитывать код несколько раз (больше двух) — перерасход затраченного времени все равно окупается против ситуаций, когда просто пытаешься выявить, что же работает не так.

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

    Ну а рантайм ошибки — быстренько глянуть код, если не обнаружил причину сразу — то только пошагово до победного конца.
  • _sg_
    27 мая 2018, 20:09
    Бросайте дебажить, пишите юнит тесты.

  • Igr
    27 мая 2018, 21:06

    тестирую в демо квике

    написал часть — запустил — проверил-пишем дальше

    практически к каждой строке коментарий

    запись в файл выполнение каждой функции, максимум записей 

     

    пишу на луа для квика, вернее пытаюсь)

      • Igr
        27 мая 2018, 22:04
        Replikant_mih, я не программист, не знаю, у меня циферку, ну может кучу циферек, но всё равно эти циферки же что то значат — значит можно подписать)
          • Igr
            27 мая 2018, 22:33

            Replikant_mih, ну в чужой программе вообще тяжело разобраться (кстати коменты очень бы помогли), а если она написана коряво — то вообще нереально 

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

              • Igr
                27 мая 2018, 22:42

                Replikant_mih, ага, я только ради возвращения и пишу)

                если к каждой строчке будет комент — то вполне возможно 

                • Михаил
                  27 мая 2018, 23:32
                  Igr, комментарии в каждой строчке первейший признак ужасного кода https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%B4_%D1%81_%D0%B7%D0%B0%D0%BF%D0%B0%D1%88%D0%BA%D0%BE%D0%BC
                  • Igr
                    28 мая 2018, 08:35
                    Михаил, возможно, но с комментариями куда как легче разобраться в чужом коде, или через продолжительное время вспомнить свой )
                    • Михаил
                      28 мая 2018, 08:58
                      Igr, код должен говорить сам за себя без всяких коментов — когда код разбит на маленькие функции с говорящими именами, переменные имеют говорящие имена ( а не просто i, j, x, y) и вместо мало понятных чисел используются константы с говорящими именами комментарии практически не нужны. 
                      • Igr
                        28 мая 2018, 09:22

                        Михаил, согласен, я далеко не профи

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

                        • Михаил
                          28 мая 2018, 09:38
                          Igr, проблема с комментариями, что при изменении кода вы должны менять комментарии, что часто забывают делать.

                          Все зависит от языка, где есть функции первого класса — переприсвойте плохое имя сторонней функции более вразумительному. Если такого синтекса в языке нет, то просто оберните вызов сторонней функции вызовом функции с понятным для вас именем. Или поставьте нормальную среду разработки, чтобы в один клик смотреть хлеп по сторонним функциям.
                          • Igr
                            28 мая 2018, 09:44

                            Михаил, пока не забывал

                             

                            функция срабатывает, например, при изменении в стакане, её не переименовать, вот к ней комент и пишу 

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

  • Чужой
    27 мая 2018, 21:08
    я по частям проверяю код, затем намного легче делать и проверять что то целое
  • Михаил
    27 мая 2018, 21:35
    Пишу тесты. Сколько-нибудь большой программе без тестов невозможно. 
      • Михаил
        27 мая 2018, 22:12
        Replikant_mih, прописная азбука программирования — код должен состоять из функций максимум в несколько строк, каждая функция должна быть покрыта тестами. 
          • Михаил
            27 мая 2018, 23:37
            Replikant_mih, есть несколько классических книг про подходы к программировани:
            Code complete 
            Clean code
            Refactoring: Improving the Design of Existing Code



  • П М
    27 мая 2018, 21:51
    По-моему ты спрашивал уже что-то подобное.
    Я стараюсь проверять по частям. 
    Хотя конечно часто бывает лень или нет сил. Но лучше проверять по частям. И потом всё вместе. 
    Потому что если жопа может стрястись, она всегда стрясается.

    В последнее время ошибки нахожу по принципу — «что-то тут такое странное какое-то, то так то сяк», а не «тут же блин вообще всё должно быть не так, почему оно так?»

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

    ошибки будут всё равно.
      • Igr
        27 мая 2018, 22:44

        Replikant_mih, сойдёт?!?   не, это не наш метод) 

        потом проблем может быть куда как больше, в разы из-за этой мелочи вроде как

      • П М
        27 мая 2018, 22:48
        Replikant_mih, да, примерно так «так сойдёт» — часто бывает. и через пару лет ошибки такие отлавливаются :)
  • KNK
    27 мая 2018, 22:03
    Разбивал код на блоки, это если речь идёт о торговой системе. Блоки такие — объявление переменных, вызов функции, индюки или события, условия входа, условия выхода, манименеджмент. Блоки стандартизированны и при добавлении нового участка кода дописываю функцию останова с индикацией. Если брал чужой индюк тестировал его логику с выводом сигнала на график. Каждая строка кода с комментариями описывающим логику. Эти простые правила очень облегчают жизнь, и сильно сокращают количество непонятных багов))
      • Igr
        27 мая 2018, 22:46

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

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

  • Unworldly
    27 мая 2018, 22:38
    Сейчас…
      • Unworldly
        27 мая 2018, 23:21
        Replikant_mih, нет, иногда отправка поста происходит случайно до его написания. ;-)
  • Евгений Шибаев
    27 мая 2018, 23:09
    Использую, если это можно так назвать,  «croud debuging». Когда мне пользователь пишет — «Жень, у тебя тут ошибка» — благодарю его за это и правлю баг.
  • facevalue
    27 мая 2018, 23:14
    ИМХО, подход не совсем корректный. Писать простыню — это мы проходили давно. ) Сейчас я делаю так:

    1. Делю задачи, которые код должен выполнить, на функции. Если сильно надо, то пишу класс или библиотеку (редкое явление).
    2. Запускаю и дебажу отдельные функции. 
    3. Когда они работают нормально, как ожидается, то уже складываю их в последовательность.

    Преимущества — дробится код, легко понять где что не работает. Не происходят такие события, когда жмешь PLAY и на экране вуду.

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

    Баланс и решение — ДРАКОН (гуглите, мощная тема). Сначала строю блок-схему кода, а потом его пишу. Благодаря процедурной логике ДРАКОНа сложно ошибиться в реализации. А уж если ошибки всплывают, то не нужно рефакторить весь код. Всплывают баги конкретные в конкретных местах. Таким образом экономится время, и разработка становится делом техники, а не творчества.

    Успехов! )
  • Unworldly
    27 мая 2018, 23:18
    ну типа каждый блок, каждый кусок кода отдельно и сразу при написании, или не сразу но отдельно, если не сразу, то когда?


    Каждую функцию отдельно и сразу при написании. Пока мысли по этой функции сидят в голове в «оперативной памяти», а не от'swap'ились на диск.

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

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

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

    Также неплохо проверить дизайн функции на наборы «нехороших» сочетаний значений входных параметров, например противоречивых, не имеющих смысла. Если таковые обнаруживаются, следует передизайнить функцию. Как минимум хотя бы на входе обработать эти ситуации и вернуть ошибку, если обнаруживается «нехорошее» сочетание.

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

    Лениться нельзя. Можно, разве, что, в качестве баловства. В программировании «лень» не прощается. Это как раз один из моментов, когда программирование положительно влияет на индивидуума.

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

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

      • Unworldly
        27 мая 2018, 23:55
        Replikant_mih, да, ещё про разбивку на функции, хотя эта мысль уже неявно звучала, но не совсем чётко.

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

        Также функции должны, в основном, образовывать иерархическую структуру. Самые низкоуровневые функции, которые, в основном, обходятся самим языком и обращениями к системе, потом функции более верхнего уровня, которые используют низкоуровневые функции, далее, функции третьего уровня, которые используют для своей реализации функции второго уровня и так далее. «Перепрыгивать» через уровень следует стараться избегать (дизайн всей программы — не очень, если так не получается).

        Ну, и, опять же, функция каждого уровня должна решать только одну задачу, это универсальное правило, от уровня не зависит.
          • Unworldly
            28 мая 2018, 01:22

            Replikant_mih, в целом, да.

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

            Если хочется более явно разграничить, можно использовать namespace'ы, если они есть в используемом языке. Классы в режиме namespace'ов тоже можно использовать, но это искусственно, уж лучше соответствующее именование, типа использования «префиксов» в именах.

            Тут, скорее, модель «иерархии библиотек» в качестве упрощённого ООП подойдёт лучше. Каждая «библиотека» предоставляет набор функций (сервисов), или API. «Библиотека», которая находится над ней, пользуется этим набором сервисов, чтобы предоставить уже свой набор функций более высокого уровня и так далее. «Библиотека» может использовать не одну, а несколько «библиотек» уровнем ниже. Получается такой упрощённый ООП, это значительно проще с точки зрения обычного мышления.

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

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

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

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

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

            Разбивка получается сверху вниз, а реализация и отладка — в обратном порядке.

              • Unworldly
                28 мая 2018, 10:56
                Replikant_mih, в целом, верно, только вычленять лучше на этапе проектирования, а не по факту упирания в необходимость. Хотя, для тренировки, полезно и поупираться, чтобы начать чувствовать, когда, во что и что вычленять.

                Классы по namespace'ам вряд ли придётся распихивать, достаточно самих классов.

                Но с классами всё сложнее. Там не только агрегирование возможно, но и наследование. Опять же, доступ к полям/методам (private, protected, public), конструкция/деструкция, а раз — классы, то обязательно — исключения… Код должен быть безопасен с точки зрения возникновения исключений… И так далее. Стоит ли оно того, чтобы всем этим и не только этим овладевать для решения своих задач?

                C# не знаю вообще, принципиально не доверяю Microsoft. И в C# могут быть свои дополнительные приколы.
                  • Unworldly
                    28 мая 2018, 23:24
                    Replikant_mih, так, а цель-то в чём? Я думал, сделать что-то надо, а не программистом стать. Ресурс, вроде, трейдерский, не программистский...

                    Программирование — огромно, оно уже переплюнуло медицину по объёму и сложности.

                    Так что только практика — ненужные знания сами отсеятся.

                    В программировании нужно понимание.
                      • Unworldly
                        29 мая 2018, 23:09
                        Replikant_mih, что ж, тоже способ выяснить для себя, что всё не так, как кажется. Кому-то требуется обязательно на своём опыте убедиться.
    • facevalue
      27 мая 2018, 23:51
      Unworldly, Снимаю шляпу. На весьма дельный вопрос — самый что ни на есть предельно профессиональный ответ.
  • Пафос Респектыч
    27 мая 2018, 23:40
    Методом пристального взгляда
      • Пафос Респектыч
        28 мая 2018, 19:00
        Replikant_mih, а других методов-то и нет, если понимаешь что делаешь ) а если не понимаешь то и тест Напида-Раса не поможет )
  • tranquility
    27 мая 2018, 23:48
    Дублирую функции так, чтобы одно и то же вычислялось разными способами. Как пример — выборку делаю бинарным поиском и прямым. Потом сравниваю логи, полученные в двух вариантах исполнения. Если они одинаковые, значит ошибки скорее всего нет)
      • tranquility
        28 мая 2018, 00:48
        Replikant_mih, уж не знаю кто более ленивый тут;) Мне, например, взападло тесткейсы придумывать. Просто на своих обычных данных прогнать и посмотреть потом «упало» что-то или нет — как-то быстрее получается в итоге, мне кажется. Алготрейдинг сам по себе не для ленивых, если дело касается разработки. А так, можно еще посоветовать объектно-ориентированный подход и вообще везде писать повторно используемый код. Так больше вероятность, что затесавшаяся где-то ошибка будет обнаружена еще до того, как система будет отправлена в бой, на этапе тестирования.
  • Тихий омут
    28 мая 2018, 07:05

    в Квике на ЛУА пошагового исполнения капец как не хватает ((
    а может я какого инструмента не знаю, чтоб пошагово можно было дебажить… У кого что есть на этот счет ?

    Я логами в DebugView  ошибки ловлю.
    Но самый капец конечно когда в простейшей функции ошибка выскакивает, типа получил Nil, а ждал стринг или инт, а функцию эту вызываешь из разных мест и вот вычислить то место которое этот nil отправило засада блин.

    • Prophetic
      28 мая 2018, 10:10
      Андрейка, Переходите на С#. Чем раньше это сделаете, тем раньше обретете спокойствие. Сам все это проходил, так что знаю о чем говорю. После того, как количество одновременно работающих роботов (с визуальными интерфейсами) превысило 10, тупиковость дальнейшей разработки на QLua стала очевидной.
  • серьёзно программировал год назад
    вставляя в код точки пишущие в файл

    и в файле читал логику на понятном языке
    буквально: «если больше тогда перешли в цикл»
    типа того

    запись в файл реализуема хоть на qbasic
    и вообще щаз вспоминаю:
    у меня 99% программ пишут в файл
  • wrmngr
    28 мая 2018, 09:42
    Если это код для реальной торговли, то полное дублирование алгоритма в Экселе
      • wrmngr
        28 мая 2018, 11:36
        Replikant_mih, зато надежный. Если алгоритм не запихивается в эксель, то в 99% случаев это не стОит вообще торговать
          • wrmngr
            28 мая 2018, 12:17
            Replikant_mih, и это тоже
  • Prophetic
    28 мая 2018, 10:25
     В целом, вопрос достаточно интересный и объемный. Я не являюсь профессиональным программистом, но мой опыт разработки торговых роботов показал, что сильно сложная и разветвленная программная среда создается далеко не сразу, а собирается из отдельных частей. Т.е. сначала мы пишем простейшего робота, и отлаживаем его работу. Потом начинаем сталкиваться с ситуациями в которых требуется усложнение логики или добавление каких-нибудь страхующих/защитных функций. Т.к. мы уже отладили общую систему, то нам остается отладить только тот кусок кода, который мы добавляем в робота. В зависимости от того, какую конкретно задачу мы пытаемся решить, пользуемся или логированием, или пошаговой отладкой, или просто онлайн-тестированием, с наблюдением (встроенные механизмы тестирования я не использую). Через какое-то время, нам приходится создавать новых роботов на основе ранее созданных, и после того как их наберется какое-то количество, мы понимаем, что есть масса кусков кода, которые перетекают из робота в робота без изменений. Такие куски выводим в отдельные функции, быстро проверяем, что они не сломались и выводим их в отдельный класс или библиотеку, после чего к отладке этих кусков уже никогда не возвращаемся.
    Таким образом, каждая новая разработка сводится к дебагингу только новых кусков кода, которые составляют лишь несколько процентов всей программы. А как именно отлаживать эти маленькие кусочки — каждый выбирает сам. Главное чтобы самому удобно было.
  • Тарас Громницкий
    28 мая 2018, 19:11

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

    Изучите базовые строительные блоки(паттерны).

    Для начала достаточно создавать отдельные классы для разных бизнес сущностей.

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

    Затем в связках, чтобы выловить проблемы взаимодействия.

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн