Как побороть программирование по стечению обстоятельств? [закрыто]

24

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

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

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

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

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

РЕДАКТИРОВАТЬ:

резюме из ваших сообщений:

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

Кстати, трудно принять ответ, это действительно трудно. Все ответы действительно хороши :)

py_script
источник
6
Люди, которые не читали книгу в течение длительного времени, могли бы получить ссылку, например, pragprog.com/the-pragmatic-programmer/extracts/coincidence .
Btilly
Если у вас нет очень короткой карьеры программиста (или вы работаете в одиночном разряде), вы, скорее всего, столкнетесь с кодом, который выглядит странно знакомым, и немного прогуляете код позже, пенни упадет: это ваше. Это не только рассмотрение с открытым исходным кодом ...
Робби Ди
@ Робби Ди. Вы можете уточнить это немного больше? Я не понимаю тебя. Действительно, у меня короткая карьера программиста, и в этом причина тега младшего программиста.
py_script
2
@py_script Я просто подчеркивал, что вы можете так же легко найти свой собственный код спустя годы (и быть потрясенным им), как и чужой. Так что, если вы начнете с хороших привычек, это принесет дивиденды позже.
Робби Ди

Ответы:

26

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

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

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

Напишите юнит-тесты. Модульные тесты отлично подходят для записи фактического поведения кода, который вы только что написали, а не идеального поведения, которое вы надеетесь найти.

Сократите цикл редактирования / компиляции / тестирования. Когда вы добавляете большой кусок кода и плохо тестируете, то есть вероятность, что он будет вести себя не так, как вы думаете. Затем вы «исправляете» это с некоторым случайным изменением, и вы получили правильный ответ на данный момент, но не представляете, как это произошло на самом деле. Вы сейчас программируете по стечению обстоятельств. Но когда вы добавляете 5 строк и затем тестируете, вероятность того, что вы получили правильный ответ, потому что он работает так, как вы думаете, работает намного лучше. По своему опыту могу сказать, что 5 блоков по 10 строк в каждой, проверенные индивидуально, - это совсем не то, что 50 строк кода, протестированных одновременно.

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

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

btilly
источник
Спасибо, действительно хороший ответ. Я думаю, что часть о цикле действительно ценна. Можете ли вы привести примеры рефакторинга, которые вы должны сделать, но это займет очень много времени, и это может кого-то обескуражить?
py_script
1
У меня много примеров. В проекте C ++ я создал классы без методов строкового преобразования. Когда я их создал, отладка стала проще, а разработка ускорилась. В проекте Perl у нас был хеш конфигурации, где у каждого разработчика была своя собственная копия каждой новой конфигурации. Добавление параметров конфигурации было проблемой, потому что вам приходилось редактировать конфигурацию каждого разработчика. Я написал систему шаблонов для хэшей, и это стало проще. В систему отчетности я добавил функцию для отображения промежуточных результатов. Моя разработка ускорилась, и я даже получил сообщение об ошибке пользователя ...
btilly
1
где финансовый отдел проследил мою логику и нашел точный запрос, по которому я ошибся, и какова была моя ошибка. (Я случайно сдавливал дублирующиеся строки UNIONтам, где мне было нужно UNION ALL.) И так далее.
Btilly
1
Внутри месяца? Я обычно нахожу, что каждый раз, когда я прикасаюсь к коду, я чувствую, что он должен подвергаться рефакторингу, но не рефакторингу, это занимает почти столько же времени, сколько и его рефакторингу.
Эми Бланкеншип
1
@ AmyBlankenship Да. Внутри месяц. Иногда смешно внутри, иногда нет. Файл конфигурации, о котором я упоминал выше, является примером «иногда нет». Мне потребовалось несколько дней, чтобы написать, документировать и протестировать новый движок шаблонов. Затем перепишите существующий конфиг, чтобы использовать его, и сделайте его намного короче, но получите точно такую ​​же структуру данных. (Это была самая трудная часть проекта.) Итак, дни пропали, без видимого результата. Тем не менее, усилия окупились всего за месяц, но с тех пор вызывают интерес.
Btilly
41

Это в значительной степени сводится к тому, чтобы не догадываться . В основном это делают новые программисты, но я видел, что ветераны тоже так делают, потому что считают, что это экономит время на исследования. Что-то не работает, поэтому вы добавляете a +1или a -1, меняете a trueв a falseили наоборот, переупорядочиваете некоторые операторы, добавляете или изменяете задержки, меняете приоритеты потоков и другие небольшие преобразования, в основном тестируя случайные перестановки, пока это не сработает.

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

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

Карл Билефельдт
источник
1
Отличный балл +1. Нигде это не применимо больше, чем исправления кода ...
Робби Ди
Правда для меня тоже, к сожалению. Чтобы быть честным, существуют объективные трудности, такие как отсутствие документации иногда. Сегодня я немного исправил свой код и пришел к выводу, что не знаю, какой параметр полезен, потому что не хватает документации. Мы просто знаем, что это число.
py_script
Я признаю. Столкнувшись с синдромом наклоняющейся зубочистки, может быть проще сложить \ s до тех пор, пока он не
заработает,
16

Самый страшный комментарий, который я когда-либо встречал в программе, был

Не трогай это. Оно работает. Мы не знаем как или почему, но это работает. 1

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

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


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

Барт ван Инген Шенау
источник
2
это также называется voodoo chicken coding c2.com/cgi/wiki?VoodooChickenCoding
minusSeven
1
Даже если кодер считает, что это правда, такие комментарии в целом бесполезны. Код может быть сложным, но если бы вы читали код иначе, вы могли бы подумать, что он прост. Все, что комментирует, это увеличивает паранойю!
Робби Ди
3
Это также может произойти при поддержке старой кодовой базы, на языке, с которым большинство нынешней команды разработчиков не очень комфортно.
pcurry
Так что резиновая утка предназначена не только для отладки. Хорошо ... Я думаю, что мы работаем над одной и той же компанией, у нас много таких комментариев: P
py_script
бывают ситуации, когда исправление просто работает из-за сбоя в API, и лучшего и логичного исправления не существует. Отладка некоторых скомпилированных сторонних библиотек может идти так же глубоко, как отладка ядра. И даже если вы обнаружили проблему, после часов отладки вы мало что можете сделать. Таким образом, вы подходите к проблеме по-другому. Вы принимаете модель «черного ящика», которая заставляет вас программировать по совпадению. Вы играете со странным поведением черного ящика, и если вам удастся заставить его работать так, как вы хотите, БОЛЬШОЙ, добавьте комментарий с «магией не трогай» и двигайся дальше.
Раду Симионеску
7

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

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

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

Иногда я обучал новых программистов, и тенденция пробовать вводить случайные вещи, чтобы увидеть, работает ли это, является обычной практикой. Они набирали строку, а затем поворачивались ко мне и спрашивали: «Будет ли это работать так?» хотя было ясно, что они понятия не имели, может ли это быть.

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

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

Себастьян Редл
источник
<< Вы должны научиться читать код, а не просто писать его. >> Итак, по поводу моего первоначального вопроса, как вы думаете, это поможет мне добавить функции в проекты с открытым исходным кодом?
py_script
2

Слишком легко кодировать, тестировать и исправлять «на гоночной трассе». У вас есть некоторые функциональные возможности, которые дают X & Y, выдают Z. Но что, если X поврежден, а Y недоступен? Что делать, если вы не можете вывести Z? Постоянно имейте в виду, что может пойти не так, и запишите это для цикла испытаний.

Ваши процедуры должны быть короткими и описательными - лучший код требует мало (если есть) комментариев.

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

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

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

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

Робби Ди
источник