Pull to refresh

Comments 86

«Накипело»?
Или реальная попытка заставить людей думать и гуглить, прежде чем задавать вопрос?
Зачем писал исходный автор — не знаю. Я решил перевести, потому что тут перечислены практически все стандартные ответы на фразу «оно не работает». Более того — не только перечислены, но и описано, почему то или другое надо попробовать, а также как именно это надо пробовать.
Скажем, если человек не знает, что полезно делить программу на кусочки в процессе отделки, то ему можно кинуть ссылку на эту статью.
Двух нету: :-)

  1. Баг в компиляторе.
  2. Баг в процессоре.

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

Как думаете, сколько времени тупил программист, когда у него 2.0 == 16.0 выдавало true? Угу, производитель ЭВМ потом тоже сильно удивлен был, ибо умудрились забыть сравнение ординат (экспонент) для вещественных чисел.
Тут всё-таки лучше быть практичным и не рассматривать события с очень малой вероятностью — а именно таким сейчас можно считать ошибку в процессоре или компиляторе. Очень малой — это меньше миллионной того, что баг у автора кода. В 50-е, да, было иначе, но сейчас не 50-е.

Кстати, уже чисто интересно с исторической точки зрения — где и когда существовала терминология, что порядок вещественного числа назывался «ординатой»? Я такого не нагугливаю, хотя времена, когда ЭВМ были большие, ещё застал лично.

<sarcasm> Разработчики компилятора OCaml тоже так думали </sarcasm>
А если серьёзно, то наивно, конечно, ожидать, что вот только начал программировать, написал 20 строчек кода и словил глюк процессора. Но не удивлюсь, если новичок, напоровшийся на undefined behavior в C, будет уверен, что наткнулся на баг в компиляторе, который неправильно компилирует.

> Разработчики компилятора OCaml тоже так думали

Ну так и я находил баг в GCC (репорт принят и подтверждён), но речь-то (без сарказма) о вероятности каждого конкретного случая…

> Но не удивлюсь, если новичок, напоровшийся на undefined behavior в C, будет уверен, что наткнулся на баг в компиляторе, который неправильно компилирует.

А так и происходит. В трекере GCC при отсылке нового тикета сразу пишут — «если ваша программа начинает работать при -fwrapv, ищите ошибку у себя», а количество закрытых на undefined behavior тикетов идёт на тысячи.
И сколько собственных багов пришлось на каждый багрепорт в GCC? Неудели и вправду миллионы?

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

А объяснять новичкам, что это не баг в компиляторе, а баг в прокладке между экраном и клавиатурой — каждому приходилось. И не один раз. Не об этом речь.
> И сколько собственных багов пришлось на каждый багрепорт в GCC? Неудели и вправду миллионы?

Ну во всяком случае больше тысячи. Как-то не считал всю длину своей карьеры, даже если ограничивать C. :)

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

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

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

> А объяснять новичкам, что это не баг в компиляторе, а баг в прокладке между экраном и клавиатурой — каждому приходилось. И не один раз. Не об этом речь.

Именно что исходная статья задаёт именно «это», о котором речь. И я стараюсь держаться в этих рамках.
Ну если багом компилятора считать internal complier error, то скорее десятки, чем тысячи. Другой момент, что проще научиться обходить баг, чем его репортить (особенно в микрософт).

Новичок новичку рознь. У нас человек попросился на практику (учится в тезникуме). Ну коллега ему и дал стыковку проца с SDRAM (другой проц, чем в примере выше). А в стыковках микросхем очень много такого, что называется «баг документации». То есть из 10 способов сделать в соответствии с докой — будут работать 1-2. А остальные — не будут. И багом это никто не считает. Обычное дело — что-то не рассказано в доке.

Такого очень много в тех же GPS-чипах или в GSM-модемах. И новичку надо понимать, что неописанных в документации особенностей — дофига.

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

А meassge такой: не надо считать, что баг в железке, документации, процессоре, компиляторе — это редчайшая экзотика. Как только вы от области, где пасутся миллионы пользователей переходите туда, где пользователей всего лишь сотни — баг становится весьма вероятен.

В подтверждение — описание эпохального бага в ИКД ГЛОНАСС (от авторов формата RINEX)

К сожалению, в интерфейсном документе ГЛОНАСС, в одной из формул была допущена ошибка в знаке.
Значения должны быть записаны в RINEX файл как -TauN, +GammaN, -TauC.
Первоначальное определение требовало указания -TauN, -GammaN, +TauC. См. параграф 8.2.


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

Почему вы уверены что все вокруг только делают что ковыряются с железками? Большинство новичков либо клепает сайты либо пишет мобильные приложения (прикладные!). Даже десктопные приложения — уже не в тренде.


И вот тут-то натолкнуться на баг в процессоре уже очень тяжело.

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

Не видели как мобильники виснут? Это не баг софта, это или банальная трещина в многослойной плате или окислились дорожки из-за попадания влаги.

Чтобы нарваться на баг в браузере — не надо быть программистом, достаточно просто много серфить. Падает и IE и FireFox и Chrome. Не так часто — но падает. Разок было не лень — кинул в багзиллу по FireFox, исправили.

А уж веб-разработка… Мама мия!!! Не, я, конечно, полный чайник в вебе. Делали мы web-интерефейс к одной железке, ну и кроме своего кода пришлось ещё и повозиться с отладкой сайта. Ну как бы проще самому исправить, чем пинать фрилансера.

Уж не знаю, баги это или не баги, но из десятка способов сделать одно и то же, во всех браузерах одинаково работал один. Остальные — или дают артефакт в одном из браузеров или вообще не работают. Самый норовистый — это, разумеется, был IE 8. Повезло — отспорили, что IE 7 не будет. :-)

Так что баг «в процессоре», знаком почти всем, у кого хватило денег на мобильник. Баги в софте — все, кто активно серфит. А вот баги в коде — только для программистов.
>но из десятка способов сделать одно и то же, во всех браузерах одинаково работал один

Ну тут скорее вопрос о соблюдении тем или иным браузером соглашений по HTML, CSS, JS… если я вас правильно понял. А сделать кроссбраузерную штуку… да еще и на несколько версий… вы, батенька, знаете толк))
Сильно раздражает, когда два часа пытаешься настроить железку через web-интерфейс, а потом выясняется, что она некорректно работает из современного Chrome, ибо сделана под FireFox.

Так что только кросброузерно. И ещё желательно угадать, чтобы хотя бы через 10 лет не перестала работать. Радиопередатчики — они такие, и по 20-30 лет живут. Почему наш интерфейс должен сдохнуть первым?
Тут, я думаю, не нужно тогда полагаться на браузер, ибо он получает ДАННЫЕ+ПРАВИЛА для их отображения, и интерпретирует эти правила сам, кто во что горазд… Вот и выходит, что выходит. Получается надо брать ДАННЫЕ в сыром виде (что-то типа json), и интерпретировать и показывать их самому. Тогда это очередной велосипед-браузер.
GUI-версия есть, просто заказчики хотели не её, а связную железку с браузерным интерфейсом. Одно из достоинств — быстрая смена компа, откуда идет управление.

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

Чтобы понять, что в современных процессорах полно багов — достаточно разок почитать errata. Вот вам на SoС, а вот на процессор.

Из недавнего от коллеги. Не проходит инициализация ОЗУ. 10 раз проверили пайку и код. Спаяли плату с другим ОЗУ по тому же стандарту JEDEC — работает. И пара реплик на форумах от американцев, что не только у нас так. Ну видимо будет в errata лишний раздел. :-)

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

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

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

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

Ордината (вместо порядка) — это термин из школьного курса математики примерно 1980ого года. Связан был скорее всего с использованием лографимической и полулографимической бумаги. А что не нагугливаете — странно. Вот вам раз, два, три, четыре, пять, шесть, семь. Забавно, что для десятичной записи меня тоже тянет использовать слово «порядок», а вот для двоичной «ордината».

Очень малой — это меньше миллионной того, что баг у автора кода.

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

«This document is only available in a PDF version to registered ARM customers.» Спасибо, но «кортинки не грузяццо» ©.
Впрочем, идею я понял. Как верно заметил yeputons@, Вы таки «страж ночи». И взгляд соответствующий.
Но я таки уверен, что автор исходной статьи подразумевал тех, кто в самом крайнем случае ищет проблемы в том, что он написал под эмулятор MIPS для университетского курса (таких валом валит в SO /assembly), а скорее всего под банальный x86, и скорее всего даже не под C. И там названные мной цифры вероятности более справедливы.

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

Именно. И они за пределами контекста.

> Ордината (вместо порядка) — это термин из школьного курса математики примерно 1980ого года. Связан был скорее всего с использованием лографимической и полулографимической бумаги. А что не нагугливаете — странно. Вот вам раз, два, три, четыре, пять, шесть, семь.

Я гуглил фразой «ордината вещественного числа» и её вариациями. Наверно, если бы ввёл «мантисса и ордината», нашлось бы. Тут, как обычно, надо заранее знать половину ответа, чтобы правильно задать вопрос :)
Что курс района 80-го года — показывает, почему я уже такого не знал — я в 80-м только в 1-й класс пошёл :) а где-то через пару лет была заметная мутация программ и учебников.
я не страж ночи — я тот редкий зверь, которому нравится отлаживать чужой код. :-)

я не уверен, что всякое DYI за пределами контекста. А в DYI вагон тех же проблем при стыковке разных микросхем. Светодиодом помигать легко, а вот следующий шаг уже может включать в себя очень много неожиданного.
А пока все дружно минусы ставили, я отписал автору очередной баг в микросхеме GPS-приемника. :-) Ну что поделать, работа у меня такая.

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

А что, у новичков другое железо? Иди другой софт? Или новички супераккуратные люди, и в отличие от остальных на баги не нарываются?

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

Ваши родители код пишут? А зависший мобильник они хоть раз видели? Вот вам и разница «в миллион раз». :-)

P.S. Зависший мобильник — это, как правило, баг железа. Трещина в плате или окислившиеся дорожки из-за попадания влаги.

%)
Ты реально тупой или придуриваешься? Речь идёт о "неправильном" поведении только что написанного новичком кода, который объясняется багом в железе.
Утверждение о зависшем мобильнике видится мне как минимум сомнительным. Все зависания, с которыми я лично сталкивался, лечились перезагрузкой.
Пожалуй, в очередной раз попрошу пруфы на статистику.

Ну да почистили память и проблема решена. Костыль, надо исправлять! (Уровень JVM/Native(Если запущенно из /system/bin) если Android либо телефон на JEEMP{Точное название не помню}, если виснет телефон с WP/W10M(Уровень ОС) то это уже нехватка памяти либо ОСь шалит, если проявляются глюки на экране или происходит ересь на аппарате то случай Jef239 (Это редко когда происходит), вирусня после прошивки{Да есть такие телефоны} производитель залил значит{Такой телефон на свалку сразу.}, вроде все варианты которые могу перечислить.)

Это дико зависит от области разработки. Кроме примеров по стыковке с хитрой микросхемой (баги железа), вот вам тот же вопрос в иной постановке.

Какие шансы, что написанный новичком сайт будет одинаково работать во всех браузерах?

Да почти нулевые. Обязательно где-то что-то не реализовано, где-то что реализовано не так, где-то что-то задокументировано не так, как реализовано…

Только если писать на C++ в рамках учебных программ на одном компиляторе — шансы налета минимальны. А на том же С++ как сразу 7 операционок и 7 компиляторов — так сразу и опаньки. Тут так отступили от стандарта, тут эдак…

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

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


Какие шансы, что написанный новичком сайт будет одинаково работать во всех браузерах?

А если новичок не использует CSS, JS, а только HTML 4.01 Strict?
Он то точно должен отображаться везде одинаково нормально.


Зависания — это прежде всего плохой контакт.

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


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

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

А если новичок не использует CSS, JS, а только HTML 4.01 Strict?
Он то точно должен отображаться везде одинаково нормально.
Если strict, а не transitional — значит уже не новичок. А отображаться одинаково — должен, вот только кому он задолжал? Явно не мне. :-)

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

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

В таком случае делают разного рода watchdog, перезагрузку одного процессора другим и так далее. Ну в общем можно сделать достаточно неубиваемо, даже несмотря на баги в коде.
Если strict, а не transitional — значит уже не новичок.

По заданию для новичков дают strict чтобы освоились, на transitional сами потом ковыляют переходят.


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

Да это искусство, но не только доступное лишь для профессионалов, просто нужно время.




В таком случае делают разного рода watchdog, перезагрузку одного процессора другим и так далее.

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


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

Так можно сделать, но нужно время.

UFO just landed and posted this here
UFO just landed and posted this here
Ну 35 лет назад я тоже думал, что баг в компиляторе или железе — это нечто особенное. Когда я в 17 лет впервые свалил компилятор — я тоже сам себе не верил. «Как это, простая опечатка — а компилятор падает. Неужели и в компиляторах бывают баги?» С тех пор — опыта как-то добавилось. И прежде всего — по умению обходить баги компиляторов и железа.

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

От сегмента зависит. Если что-то используют сотни тысяч людей — вряд ли там есть баг. А если ты в первом десятке, кто использует API — багов там найдется немерянно. Ну хотя бы вида «может оно так и задумывалось, но какого черта не описали?!».

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

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

Очень забавно, что «баг» нашелся в стандарте С++.

Не могу удержаться от цитаты...
в синтаксисе есть неоднозначности. Это надо оценить: в Стандарте (!) языка программирования прямо написано, что некоторые конструкции можно трактовать двояко — либо как объявление, либо как оператор!

В несколько упрощенном виде формулировка из стандарта выглядит так:
«выражение, содержащее в качестве своего самого левого подвыражения явное преобразование типа, которое записано в функциональном стиле, может быть неотличимо от объявления, в котором первый декларатор начинается с левой круглой скобки». Классический пример: что такое T(a); если T — некоторый тип? С одной стороны, это как бы объявление переменной с именем a, тип которой задан как T. С другой — конструкцию можно трактовать как преобразование типа уже объявленной где-то ранее переменной a к типу T.

Ну вы же понимаете, что статья не о тех случаях, о которых вы говорите? :-)

Гм, вы думаете, что со всякими ардуино и малинкой возятся бородатые гуру со стажем в embeded 20 лет? Тогда удивлю: их уже школьникам преподают. А шансы нарваться на баги железа — как во взрослом embeded.

БОНУС: никому не интересная история, как я сам был в роли чайника на JS
Уже писал, что пару лет назад я был как раз в роли чайника — было проще самому править баги в веб-интерфейсе, чем просить фрилансера (собственно моя часть бала сишная). Ну в общем сделать так, чтобы работало во всех браузерах — это была такая боль… IE8, IE9, IE10, Chrome, FireFox, Opera, Safari… Причем постоянно — работает везде, кроме одного. Причем этот один — все время разный.

Не знаю уж, как это классифицировать, как баги в браузерах или лакуны в документации к ним.

Ладно, отладился, повезли ставить. А там оказалась чуть более старая версия IE8. И никаких шансов на обновление — ибо береговая радиостанция морской связи. Ну в общем заработало почти всё. Но не всё. :-)

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


P.S. Более того, начинать учить деток прямо с ардуино — это верный путь. Только про баги железок забывать не надо.
Почему то вдруг вспомнилось
Где то в 2006 году когда у меня был отлажен алгоритм на GPU для которого нужен был работающий X server, американский коллега (тоже программист с большим стажем) из моей же компании спрашивает " а как запустить эту программу X?". Я ему ответил чтоб принципе достаточно набрать «X (uppercase ) а затем „enter“
Нет ни одной причины, по которой корректная программа в 20 строк кода могла бы получить предупреждение компилятора.


Есть: «переменная нигде не используется».

разбить код на методы поменьше


20 строк кода разбить код на методы поменьше? Сколько методов м.б. в программе в 20 строк?!

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


Будет! И до StackOverflow (и кроме) этим занимаются много добрых людей (и я в том числе) — 20 строк кода в знакомой мне задаче — полная ерунда. Специально не ищу, но если случайно попалось на глаза и сразу вижу ошибку, то почему не помочь? Тем более, что на некоторых сайтах за такую помощь плюсуют — мне приятно, а человеку польза…

Поэтому: не бойтесь спрашивать по существу!

Есть: «переменная нигде не используется».

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

20 строк кода разбить код на методы поменьше? Сколько методов м.б. в программе в 20 строк?!

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

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


+1

Поэтому: не бойтесь спрашивать по существу!


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

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


Верно. Я только придрался к утверждению «Нет ни одной причины...» Т.е., если в программе есть лишние переменные, то они не помешают правильной работе.

В крайнем случае: одна строка — один метод.


Зависит от языка и от принятых форматов («елочка») в этом языке. У меня простейшие методы больше занимают:

 procedure TGraph.addEdge (v,u : integer);
begin
   addEdgeA (v,u);
  public
    procedure addEdge (v,u : integer); // добавить ребро (v,u)
end;


+ определение класса:

TGraph = class(TObject)
  protected
    procedure addEdgeA (v,u : integer); virtual; abstract;
  end;


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


Полностью согласен. Обязательно надо научиться.

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


Ok. И не только языка, но и библиотек. Можно проработать 10 лет и хорошо уметь отлаживать самостоятельно, но подключаешь новую библиотеку, которую не использовал, т.к. не было задачи, и оказываешься новичком.

Листинги перекосило:

Первый:

procedure TGraph.addEdge (v,u : integer);
begin
   addEdgeA (v,u);
end;


второй:

TGraph = class(TObject)
  protected
    procedure addEdgeA (v,u : integer); virtual; abstract;
  public
    procedure addEdge (v,u : integer); // добавить ребро (v,u)
  end;


(Почему на Хабре так мало времени на редактирование? -Инет бывает ооооочень задумчив!)
Работе-то лишние переменные не мешают — а вот на MCVE программа с лишними переменными не тянет.
По-моему, это отличный повод убрать эту переменную нафиг и уменьшить количество строк в программе. Если она не используется и ни на что не влияет, то в отладке будет мешать.

unique_lock<mutex> lock(_mutex);
признаться, не наблюдал чтоб компиляторы ругались ворнингами на локи. А вот syntax highlighter'ы ругаются

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

Например, такую пошаговую отладку:

for i:=1 to 1000000 do
 a[random(1000000)] := a[random(1000000)] ;


;)

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

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


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

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

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

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

На русском SO и Тостере нередко встречается ещё более весёлый вариант вопроса:
Есть задача, но сделать почему-то не получается! Помогите!!!
[0 строк кода]
Даже еще лаконичнее встречаются:
Есть задача.
[всё, на этом конец]

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

Давно не студент, но делаю точно также — ищу код, который делает тоже самое или близкое к тому, что мне надо, потом адаптирую решение. И да, чужой код не всегда понятен.
А особенно, если чужой код из 5 строчек с вызовом внешней библиотеки. Как должна себя вести библиотека на зоопарке разных ОС, с разными аудиодрайверами (PulseAudio, Alsa) и разным набором установленных программ — заранее неизвестно.
Не хватает ещё одного совета, ИМХО. Убедитесь, что вы не занимаетесь преждевременной оптимизацией и не используете при этом фичи, которые не понимаете. Классический пример на питоне:

>>> a = 2
>>> b = 2
>>> a is b
True
>>> a = 1e10
>>> b = 1e10
>>> a is b
False


Сам так тупил в процессе изучения питона. Я знал, что сравнение объектов требует вызова __eq__(), что относительно долго, и что для int меньше какого-то порога (который я и сейчас не помню) is всегда True, когда == True. Ну ведь абсолютно логично и безопасно допустить, что в условном физбаззе значения рассматриваемого числа не выйдут за этот самый порог. Можно сэкономить пару-тройку тактов.

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

Причина немного в другом. Python всегда держит все целые от -5 до 256, поэтому a и b по сути действительно будут ссылаться на один и тот же объект, который был преаллоцирован при запуске и is выдаст True. Убедиться можно вызвав id(a) и id(b). 1e10 же действительно надо создать.

Ну не знаю, на python 2.7 это не так

a = 2
b = 2
print id(a), id(b)
print a is b

a2 = 1e10
b2 = 1e10
print id(a2), id(b2)
print a2 is b2

На выходе получаю

31424480 31424480
True
31485288 31485288
True

В ранних версиях интерпретатора Python 2/3 возможно был такой баг


a = b = 1e10 
a == b # False

Когда мы ждем True


Но в последних версиях такого я пока не встречал.

Я проверял на 2.7.14, Win 7 Pro.

Я говорю что раньше был такой баг, а не словил его только что.


Кстати раз указали версию Python
Python 2.7.14
Python 3.6.2
ArchLinux rolling


Ловил этот баг я на версии: Python 2.6.xx
Номер патча не помню, но тогда использовал тот же дистрибутив.

Поведение отличается в интерактивном режиме и при работе скрипта. В случаи с 1e10 — в интерактивном режиме будет False, в скрипте — True. Справедливо для 2.7.14 и 3.4.6 как минимум, но вероятно и для 3.5/3.6 будет таким же.

Кстати, подобного поведения (id(a2)==id(b2)) можно добиться и в интерактивном режиме, достаточно обернуть этот код в функцию. Тогда он просто при подготовке байткода соберет все константы (их можно посмотреть в структуре function_name.__code__.co_consts) и соптимизирует аллокацию. С запуском скрипта, скорее похожая процедура, но уже на уровне модуля.

(del, по сути подтверждаю, что в интерактивном id различаются, из скрипта — нет)
Бывает, что вроде проще ответ поискать в интернете. Но на форуме тебе могут посоветовать очень полезные вещи, которых в интернете ты почему-то не можешь сразу найти.
Неэффективно тратить большое количество времени на поиск ошибок, если есть технологии поиска ошибок в сети.
Я думаю, что если невозможно найти ошибку за 15 минут, то стоит прибегнуть к помощи профи.

То есть, стать профи самому планов нет?

Вопрос по фраза «включите все предупреждения компилятора» — в С++ есть несколько уровней компиляции? (вообще, есть такое понятие уровни компиляции?)
В компиляторах обычно есть множество различных предупреждений, которые они умеют выдавать. Некоторые включены по умолчанию, некоторые выключены. Разными флагами можно включать разные поднаборы. Скажем, в GCC даже флаг -Wall включает далеко не всё, но уже больше, чем по умолчанию.
Для gcc большую часть предупреждений включит сочетание "-Wall -Wextra" и опционально можно добавить "-pedantic" (будет еще ругань на использование gccизмов). Еще хорошей идеей можно считать включение в дебаг-сборках всяких ubsan (undefined behavior sanitizer), asan (address) и tsan (threads), но к сожалению можно включать только 1 за раз.
Санитайзерам нужна поддержка на уровне библиотеки? Они с NewLib работают?
Хм, честно говоря я вопросом этим никогда не задавался, но кажется что не нужна. Это отдельные библиотеки с которыми, в том числе, надо линковаться. Если они с NewLib соберутся, то должны работать.
Почти все советы из книги Программист-Прагматик, причём, кажется даже в том же порядке, в каком и даются эти советы в главах… Странное совпадение, просто как раз сейчас читаю эту книгу)
Спасибо за перевод. Поставили на него ссылку в справке ru.SO
Очевидно напрашивается следующий вывод: работающая маленькая программа на 20 строчек — это часть более крупной программы из 20 строчек. Когда разработчик овладевает искусством писать 20-строчные программы без ошибок, он овладевает искусством писать любые программы.
Большинство программистов естественным образом полагают, что их код работает, как ожидается

В работе чаще всего сталкиваюсь с обратным:

Первое правило программиста: Твоя программа всегда содержит ошибки и работает не так, как ожидается.

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

Третье правило программиста: Если твоя интуиция кричит, что там есть баг, то он там 100% есть, ибо см. правило №1. И ты этот баг уже нашел, но еще не осознал в чем именно он заключается.
Sign up to leave a comment.

Articles