Чисто программирование при написании научного кода

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

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

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

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

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

Требуется ли модульное тестирование для написания небольших фрагментов кода? Как насчет ООП? Какие подходы хороши для быстрого написания хорошего, чистого кода при выполнении «научного программирования», а не для работы над более крупными проектами?

Я задаю эти вопросы, потому что часто само программирование не является сложным. Это больше о математике или науке, которую я тестирую или исследую с помощью программирования. Например, это класс, необходимый, когда две переменные и функция могут, вероятно, позаботиться об этом? (Считайте, что это также обычно ситуации, когда скорость программы предпочтительнее, чтобы быть на более быстром конце - когда вы выполняете 25 000 000 + временных шагов моделирования, вы как бы хотите, чтобы это было.)

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

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


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

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


Update

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

Я также установил pylint и запускал его во всем моем коде. Первоначально изначально был получен отрицательный результат; Я даже не знаю, как это возможно. Мой основной файл начинался со счетом 1,83 /10 и теперь составляет ~ 9,1 /10. Весь код теперь хорошо соответствует стандартам. Я также натолкнулся на это своими глазами, обновляя имена переменных, которые ушли ... uhm ... awry, и искали разделы для рефакторинга.

В частности, я задал недавний вопрос на этом сайте по рефакторингу одной из моих основных функций, и теперь он намного чище и намного короче: вместо длинной, раздутой, if /else заполненной функции, теперь менее чем в два раза меньше, и намного легче понять, что происходит.

Мой следующий шаг - это реализация «модульного тестирования». Под этим я подразумеваю файл, который я могу запустить в своем основном файле, который рассматривает все функции в нем с операторами assert и try /excepts, что, вероятно, не самый лучший способ сделать это, и приводит к большому дублированию кода, но я буду продолжать читать и пытаться выяснить, как это сделать лучше.

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

Итак ... Я думаю, это все, что можно сказать: спасибо .

151 голос | спросил heather 6 J000000Friday18 2018, 03:56:09

23 ответа


152

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

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

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

Ваша основная проблема будет читабельна, вот несколько советов по улучшению:

Переменные имена:

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

Разделите свой код на функции:

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

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

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

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

Глобальные переменные:

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

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

Контроль версий

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

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

ответил BgrWorker 6 J000000Friday18 2018, 10:20:17
132
Физик здесь. Был там.

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

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

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

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

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

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

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

ответил Edgar Bonet 6 J000000Friday18 2018, 14:25:06
80

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

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

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

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

ответил Karl Bielefeldt 6 J000000Friday18 2018, 05:15:12
26
  

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

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

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

  

Требуется ли модульное тестирование для написания небольших фрагментов кода? Как насчет ООП? Какие подходы хороши для быстрого написания хорошего, чистого кода при выполнении «научного программирования», а не для работы над более крупными проектами?

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

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

ответил Peter Taylor 6 J000000Friday18 2018, 11:27:16
15

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

Если вы пишете сценарии для выполнения научных вычислений, у вас, вероятно, есть документы с используемыми вами уравнениями или алгоритмами. Если вы используете новые идеи, которые обнаружили сами по себе, вы, надеюсь, опубликуете их в своих собственных документах. В этом случае правило: Вы хотите, чтобы ваш код читался так же сильно, как опубликованные уравнения, насколько это возможно. Вот ответ на Software Engineering.SE с более чем 200 upvotes, выступающими за этот подход и объясняющими, что это выглядит так: Есть ли оправдание для коротких имен переменных?

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

ContactGeometry.cpp:

 // t = (-b +/- sqrt(b^2-4ac)) / 2a
// Discriminant must be nonnegative for real surfaces
// but could be slightly negative due to numerical noise.
Real sqrtd = std::sqrt(std::max(B*B - 4*A*C, Real(0)));
Vec2 t = Vec2(sqrtd - B, -sqrtd - B) / (2*A);

ContactGeometry_Sphere.cpp:

 // Solve the scalar Jacobi equation
//
//        j''(s) + K(s)*j(s) = 0 ,                                     (1)
//
// where K is the Gaussian curvature and (.)' := d(.)/ds denotes differentiation
// with respect to the arc length s. Then, j is the directional sensitivity and
// we obtain the corresponding variational vector field by multiplying b*j. For
// a sphere, K = R^(-2) and the solution of equation (1) becomes
//
//        j  = R * sin(1/R * s)                                        (2)
//          j' =     cos(1/R * s) ,                                      (3)
//
// where equation (2) is the standard solution of a non-damped oscillator. Its
// period is 2*pi*R and its amplitude is R.

// Forward directional sensitivity from P to Q
Vec2 jPQ(R*sin(k * s), cos(k * s));
geod.addDirectionalSensitivityPtoQ(jPQ);

// Backwards directional sensitivity from Q to P
Vec2 jQP(R*sin(k * (L-s)), cos(k * (L-s)));
geod.addDirectionalSensitivityQtoP(jQP);

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

ответил Kevin 8 J000000Sunday18 2018, 08:51:56
14
  

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

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

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

  • Масштабируемость. Является ли сценарий самостоятельным, или он в конечном итоге будет использоваться в более крупной программе? Если это так, это большее программирование с использованием ООП? Может ли код в вашем скрипте легко интегрироваться в большую программу?
  • Модульность: в общем, ваш код должен быть модульным. Тем не менее, ООП разбивает код на куски особым образом. Способствует ли этот тип модульности (т. Е. Разбивает ваш скрипт на классы), что вы делаете?
  

Я хочу знать, как «начать заново» и четко прописывать эти   меньшие, более быстрые проекты.

# 1: ознакомьтесь с тем, что там есть:
Несмотря на то, что вы просто «скриптируете» (и вы действительно просто заботитесь о компоненте науки), вам нужно потратить некоторое время, чтобы узнать о различных концепциях программирования и парадигмах. Таким образом, вы можете лучше понять, что вам следует /не следует использовать и когда. Это может показаться немного сложным. И у вас все еще может возникнуть вопрос: «С чего начать /на что я начинаю смотреть?» Я пытаюсь объяснить хорошую отправную точку в следующих двух пунктах.

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

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

# 4: Ищите консорциумов:
Я не знаю, в какой научной области вы находитесь. Но в зависимости от того, что вы делаете в научном мире, попробуйте искать консорциумы, рабочие группы или участников конференции. Затем посмотрите, есть ли какие-либо стандарты, над которыми они работают. Это может привести к некоторым стандартам кодирования. Например, я делаю много геопространственной работы. Взглянув на документы конференции и рабочие группы, я привел меня в Open Geospatial Consortium . Одна из вещей, которые они делают, - это работа над стандартами для геопространственного развития.

Я надеюсь, что это поможет!


Замечание: Я знаю, что вы просто использовали ООП в качестве примера. Я не хотел, чтобы вы думали, что я застрял в том, как обращаться с написанием кода с помощью ООП. Было просто написать ответ, продолжающийся на этом примере.
ответил JustBlossom 6 J000000Friday18 2018, 05:17:30
14

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

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

С этой целью, если вы хотите что-то конкретное, ориентированное на исследователей, а не на общих разработчиков программного обеспечения, я не могу рекомендовать Software Carpentry достаточно высоко. Если вы можете посетить один из семинаров , отлично; если у вас есть время /доступ к чтению, прочитайте некоторые из своих статей в лучшие примеры научных вычислений , это тоже хорошо. Из последнего:

  

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

     

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

     

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

Конспект высокого уровня рекомендуемой практики:

  1. Написать программы для людей, а не компьютеров
  2. Пусть компьютер выполняет работу
  3. Сделать инкрементные изменения
  4. Не повторяйте себя (или другие)
  5. Планирование ошибок
  6. Оптимизировать программное обеспечение только после его правильной работы.
  7. Дизайн и назначение документов, а не механика
  8. Сотрудничать

В статье подробно рассматривается каждая из этих точек.

ответил David Moles 6 J000000Friday18 2018, 20:12:46
14

Я бы рекомендовал придерживаться принципа Unix: Keep It Simple, Stupid! (ПОЦЕЛУЙ)

Или, по-другому: Делайте одно за раз, и делайте это хорошо.

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

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

Как вы разделите длинную функцию? Ну, сначала вы ищете повторяющиеся шаблоны кода. Затем вы выставляете эти шаблоны кода, даете им описательное имя и смотрите ваш код shrink . Действительно, лучшим рефакторингом является рефакторинг, который уменьшает размер кода.

Это особенно актуально, если запрограммированная функция была запрограммирована с помощью copy-paste. Всякий раз, когда вы видите такой повторяющийся образец, вы сразу же знаете, что это, вероятно, должно быть превращено в собственную функцию. Это принцип Не повторяйте себя (DRY) . Всякий раз, когда вы нажимаете копирование, вы делаете что-то неправильно! Вместо этого создайте функцию.

  

Анекдот
  Я когда-то провел несколько месяцев рефакторинг кода, который имел функции около 500 строк каждый. После того, как я закончил, общий код был примерно на тысячу строк короче; Я произвел отрицательный результат в терминах строк кода. Я был обязан компании ( http: //www.geekherocomic. ком /2008/10 /09 /программисты-зарплата-политика /index.html ). Тем не менее, я твердо верю, что это была одна из моих самых ценных работ, которые я когда-либо делал ...

Некоторые функции могут быть длинными, потому что они выполняют несколько разных действий один за другим. Это не СУХИЕ нарушения, но они также могут быть разделены. Результатом часто является функция высокого уровня, которая вызывает несколько функций, реализующих отдельные шаги исходных функций. Это, как правило, увеличивает размер кода, но добавленные имена функций творят чудеса, делая код более удобочитаемым. Потому что теперь у вас есть функция верхнего уровня со всеми ее явными именами. Кроме того, после этого разделения ясно, какой шаг работает на какие данные. (Аргументы функции. Вы не используете глобальные переменные, не так ли?)

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

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

Наконец, запишите каждое действие с фиксацией. Вы выставляете что-то в новую функцию, это фиксация . Вы объединяете две функции в одну, потому что они действительно делают то же самое, это фиксация . Если вы переименуете переменную, это commit . Зафиксировать часто. Если день проходит, и вы не совершаете, вы, вероятно, сделали что-то не так.

ответил cmaster 6 J000000Friday18 2018, 17:23:01
9

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

  • Не нужно сохранять список изменений, или иметь много копий файла и т. д., так как это контролирует управление версиями.
  • Больше не потеряно файлов из-за перезаписей и т. д. (если вы просто придерживаетесь основ, например, избегаете «переписывания истории»)
  • Нет необходимости в устаревших комментариях, мертвом коде и т. д. «на всякий случай»; как только они будут преданы контролю версий, не стесняйтесь их уничтожать. Это может чувствовать себя очень свободным!

Я бы сказал, не переусердствуйте: просто используйте git. Придерживайтесь простых команд (например, только одна ветвь master), возможно, используйте графический интерфейс, и все должно быть в порядке. В качестве бонуса вы можете использовать gitlab, github и т. Д. Для бесплатной публикации и резервного копирования;)

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

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

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

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

Вы упоминаете скорость как фактор, и в этом случае проверка утверждения может быть нежелательной в этом цикле (но все же полезна для проверки установки и последующей обработки). Однако почти все реализации утверждений дают возможность отключить их; например в Python , они могут быть отключены с помощью -O (я не знал этого, так как я никогда не чувствовал необходимости отключать какие-либо из моих утверждений раньше). Я бы рекомендовал оставить их по по умолчанию; если ваш цикл кодирования /отладки /тестирования замедляется, вам может быть лучше провести тестирование с меньшим подмножеством ваших данных или выполнить меньшее количество итераций некоторого моделирования во время тестирования или что-то еще. Если вы в конечном итоге отключите утверждения в не-тестовых прогонах по соображениям производительности, первое, что я рекомендую вам сделать, это measure , если они на самом деле являются источником замедления! (Очень легко обманывать себя, когда дело доходит до узких мест производительности)

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

Системы, подобные Nix, только недавно стали (немного) популярными, и некоторые из них могут считать их излишними для «выброса» кода, как вы описываете, но их преимущество в отношении воспроизводимости научных вычислений огромно. Рассмотрим сценарий оболочки для запуска эксперимента, например этот (например, run.sh):

#!/usr/bin/env bash
set -e
make all
./analyse < ./dataset > output.csv

Мы можем переписать его в «деривацию» Nix, вместо этогоэто (например, run.nix):

with import <nixpkgs> {};
runCommand "output.csv" {} ''
  cp -a ${./.} src
  cd src
  make all
  ./analyse < ./dataset > $out
''

Материал между ''...'' представляет собой код bash, такой же, как и раньше, за исключением того, что ${...} можно использовать для «сращивание» в содержимом других строк (в данном случае ./.), который будет расширяться до пути к каталогу, содержащему run.nix). Строка with import ... импортирует стандартную библиотеку Nix , которая предоставляет runCommand для запуска кода bash. Мы можем запустить наш эксперимент, используя nix-build run.nix, который выдаст такой путь, как /nix/store/1wv437qdjg6j171gjanj5fvg5kxc828p-output.csv.

Так что это нас покупает? Nix автоматически настроит «чистую» среду, которая имеет доступ только к вещам, о которых мы явно просили. В частности, он не имеет доступа к таким переменным, как $HOME или любому системному программному обеспечению, которое мы установили. Это делает результат независимым от деталей нашей текущей машины, например, содержимого ~/.config или версий программ, которые мы установили; AKA - материал, который мешает другим людям воспроизводить наши результаты! Вот почему я добавил, что команда cp, так как проект не будет доступен по умолчанию. Может показаться раздражающим, что программное обеспечение системы не доступно для сценария Nix, но оно идет наоборот: нам не нужно что-либо, установленное в нашей системе (кроме Nix), чтобы использовать его в скрипте; мы просто просим об этом, и Nix уйдет и выберет /скомпилирует /все, что необходимо (большинство вещей будут загружены как двоичные файлы, а стандартная библиотека также огромна!). Например, если нам нужны куча конкретных пакетов Python и Haskell для некоторых версий этих языков, а также некоторые другие нежелательные (потому что почему бы и нет?):

with import <nixpkgs> {};
runCommand "output.csv"
  {
    buildInputs = [
      gcc49 libjson zlib
      haskell.packages.ghc802.pandoc
      (python34.withPackages (pyPkgs: [
        pyPkgs.beautifulsoup4 pyPkgs.numpy pyPkgs.scipy
        pyPkgs.tensorflowWithoutCuda
      ]))
    ];
  }
  ''
    cp -a ${./.} src
    cd src
    make all
    ./analyse < ./dataset > $out
  ''

Тот же nix-build run.nix будет запускать это, получая все, что мы просили сначала (и кэшируем его все, если мы захотим его позже). Вывод (любой файл /каталог с именем $out) будет сохранен в Nix, который является его дорогой. Он идентифицируется криптографическим хешем всех входных данных, которые мы запрашивали (содержимое сценария, другие пакеты, имена, флаги компилятора и т. Д.); эти другие пакеты идентифицируются хэшами их входов и т. д., так что у нас есть полная цепочка провиновения для всего, вплоть до версии GCC, которая скомпилировала версию GCC, которая скомпилировала bash, и так далее!

Надеюсь, я показал, что это очень много для научного кода, и с этим легко начать работу. Это также начинает очень серьезно восприниматься учеными, например. (верх Google) https://dl.acm.org/citation.cfm?id= 2830172 , так что это может быть ценным умением культивировать (как и программирование).

ответил Warbo 6 J000000Friday18 2018, 22:00:29
6

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

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

ответил Mathias Ettinger 6 J000000Friday18 2018, 11:28:18
4

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

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

Что вам тогда пригодится?

  • контроль версий хорош, поскольку он позволяет вам очень легко создавать резервные копии своей работы. По состоянию на 2018 год github - очень популярное место для этого (и вы всегда можете переместить его позже, если это необходимо - git очень гибкий). Дешевой и простой заменой резервных копий являются процедуры автоматического резервного копирования в вашей операционной системе (Time Machine for Mac, rsync для Linux и т. Д.). Ваш код должен быть в нескольких местах!
  • Модульные тесты хороши, потому что, если вы пишете их first , вам придется подумать о том, как проверить, что на самом деле делает код, что поможет вам разработать более полезный API для вашего кода. Это полезно, если вы когда-нибудь заработаете код для повторного использования позже.
  • Документация. Научитесь писать соответствующую документацию на языке программирования, который вы используете (например, javadoc для Java). Напишите на будущее вас. В этом процессе вы обнаружите, что хорошие имена переменных упрощают документирование. Итерация. Дайте такое же количество внимания вашей документации, как поэтесса к стихам.
  • Используйте хорошие инструменты. Найдите IDE, чтобы помогал вам и хорошо учился. Рефакторинг, такой как переименование переменных для лучшего имени, намного проще.
  • Если у вас есть сверстники, подумайте об использовании экспертной оценки. Имея постороннего взглянуть на ваш код и понять его, это настоящая версия будущего, о котором вы пишете. Если ваш коллега не понимает ваш код, вы, вероятно, не будете позже.
ответил Thorbjørn Ravn Andersen 6 J000000Friday18 2018, 11:42:36
3

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

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

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

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

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

ответил whatsisname 6 J000000Friday18 2018, 04:30:35
3

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

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

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

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

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

ответил Aidan 6 J000000Friday18 2018, 13:20:21
3

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

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

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

Linter смотрит на код, который вы написали, и сравнивает его с настраиваемым набором лучших практик. Если у linter есть правило, что переменные должны быть camelCase, и вы пишете его в snake_case, он будет отмечать это как ошибку. Хорошие литеры имеют правила от «объявленных переменных должны быть использованы» до «Цикломатическая сложность функций должна быть меньше 3».

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

ответил Mike Gossmann 8 J000000Sunday18 2018, 19:22:33
3

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

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

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

ответил Bob Newell 9 J000000Monday18 2018, 04:23:38
3

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

  

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

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

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

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

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

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

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

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

  

Как насчет ООП?

OOP - это способ думать о разных объектах, например:

  

Когда Customer хочет приобрести Product, он говорит с Vendor, чтобы получить Order. Затем Accountant оплатит Vendor.

Сравните это с тем, как функциональный программист думает о вещах:

  

Когда клиент хочет purchaseProduct(), он talktoVendor(), чтобы он sendOrder() ему. Аккаунт затем будет payVendor().

Яблоки и апельсины. Ни один из них объективно не лучше другого. Интересно отметить, что для ООП код Vendor упоминается дважды, но он относится к одному и тому же. Однако для функционального программирования talktoVendor() и payVendor() - это две разные вещи.
Это демонстрирует разницу между подходами. Если между этими двумя действиями существует много логики, зависящей от поставщика, тогда ООП помогает уменьшить дублирование кода. Однако, если между ними нет общей логики, то объединение их в один Vendor является бесполезной работой (и, следовательно, более эффективное программирование).

Чаще всего математические и научные вычисления представляют собой различные операции, которые не зависят от неявной общей логики /формулы. Из-за этого функциональное программирование чаще используется, чем ООП.

  

Какие подходы хороши для написания хорошего, чистого кода быстро при выполнении «научного программирования», а не для работы над более крупными проектами?

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

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

Тот же аргумент возвращается сюда.

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

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

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

  

Например, это класс, необходимый, когда две переменные и функция могут, вероятно, позаботиться об этом?

Принципы OOP в стороне, основная причина, по которой я пишу классы для размещения нескольких значений данных, заключается в том, что она упрощает декларирование параметров метода и возвращаемых значений. Например, если у меня есть много методов, которые используют местоположение (пара lat /lon), то я быстро устану от необходимости вводить float latitude, float longitude и предпочитает писать Location loc.

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

  

Например, это класс, необходимый, когда две переменные и функция могут, вероятно, позаботиться об этом?

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

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

  

(Считайте, что это также обычно ситуации, когда скорость программы предпочтительнее, чтобы быть на более быстром конце - когда вы используете 25 000 000+ временных шагов моделирования, вы как бы хотите, чтобы это было.)

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

В этом смысле не имеет значения, используете ли вы ООП или нет. Объем памяти остается прежним.

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

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

Для Python специально вам не нужно явно компилировать код перед его вызовом. Однако, когда вы не предварительно компилируете, компиляция произойдет при попытке выполнить код. Когда я говорю «runtime», я имею в виду само выполнение, а не компиляцию, которая может предшествовать исполнению.

ответил Flater 9 J000000Monday18 2018, 10:37:06
3

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

Например, вам может потребоваться много преобразований координат в вашей области (ECEF, NED, lat /lon, WGS84 и т. д.), поэтому функция типа convert_ecef_to_ned() должен перейти в новый проект под названием CoordinateTransformations. Поместите проект под контроль версий и разместите его на серверах своего отдела, чтобы другие люди могли использовать (и, надеюсь, улучшить) его. Затем через несколько лет у вас должна быть надежная коллекция библиотек с вашими проектами, содержащая только код, специфичный для конкретной области проблем /исследований.

Еще один общий совет:

  • Всегда старайтесь точно моделировать свою конкретную проблему так же точно, как возможно, независимо от того, что это такое. Таким образом, разработка программного обеспечения такие вопросы, как то, что /где /как поставить переменную, должно стать гораздо более очевидным для ответа.
  • Я бы не стал беспокоиться о разработке тестов, поскольку научный код описывает идеи и концепции и более творческий и жидкий; нет API-интерфейсов для определения, услуг поддерживать, риски для кода других людей при изменении функциональности и т. д.
ответил nobism 6 J000000Friday18 2018, 09:48:13
3

Преимущества чистого научного кода

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

  •   
  • ... действительно ли имеет смысл писать код, который, как говорят, ООП, если бы какой-то стандартный материал мог быть выполнен, было бы намного быстрее писать и было бы аналогичным уровнем удобочитаемости из-за краткость программы?

  •   

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

  • Почему они открыли этот файл?
  • Что они ищут?

Из моего опыта,

Чистый код должен упростить проверку ваших результатов

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

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

Чистый код может служить примером кода для будущих кодеров

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

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

Рекомендации

«Цитируйте» математические формулы, используя комментарии.

  • Добавить комментарии к математическим формулам «cite», особенно если вы использовали оптимизацию (триггерные тождества, серии Тейлора и т. д.).
  • Если вы получили формулу из книги, добавьте комментарий, в котором говорится, что John Smith Method from Some Book 1st Ed. Section 1.2.3 Pg 180, если вы нашли формулу на веб-сайте или в документе, процитируйте это также.
  • Я бы рекомендовал избегать комментариев только «ссылка», убедитесь, что вы ссылаетесь на метод по имени где-то , чтобы позволить людям использовать его в Google, я столкнулся с некоторыми комментариями «ссылка только», которые перенаправлены на старые внутренние страницы, и они могут очень расстраивать .
  • Вы можете попытаться ввести формулу в свой комментарий, если ее еще легко прочитать в Unicode /ASCII, но это может стать очень неудобным (комментарии кода не являются LaTeX).

Использовать комментарии мудро

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

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

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

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

  

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

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

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

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

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

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

Использовать контроль версий

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

Преимущества:

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

Соблюдайте осторожность при копировании /вклеивании кода

  

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

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

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

ответил jrh 11 J000000Wednesday18 2018, 03:12:57
2

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

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

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

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

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

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

ООП - это повторное использование кода, абстрагирование, инкапсуляция, факторинг и т. д. Очень полезно, но легко заблудиться, если производить качественный код и amp; дизайн - не ваша конечная цель. Требуется время & усилия по производству качественных материалов.

ответил copper.hat 8 J000000Sunday18 2018, 23:31:52
2

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

Но мне действительно нравятся интеграционные тесты для научного кода:

Изолируйте небольшой фрагмент вашего кода, который может работать на нем, например. трубопровод ETL. Затем напишите тест, который предоставляет данные, запустите etl-конвейер (или просто шаг), а затем проверьте, соответствует ли результат вашим ожиданиям. Хотя проверенный фрагмент может быть большим количеством кода, тест предоставляет все еще значение:

  1. У вас есть убедительный крючок для повторного выполнения кода, который часто запускает его.
  2. Вы можете проверить некоторые допущения в своем тесте
  3. Если somethink breaks, легко добавить неудачный тест и исправить
  4. Вы кодифицируете ожидаемые входы /выходы, избегая обычной головной боли, которая возникает из-за попытки угадать формат входных данных.
  5. Несмотря на то, что IT-тесты по-прежнему не такие худые, как ИТ-тесты, они помогают разбить ваш код и заставить вас добавить некоторые ограничения в свой код.

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

ответил Christian Sauer 9 J000000Monday18 2018, 16:41:11
2

Какие качества важны для такого рода программ?

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

Вероятно, не имеет значения, насколько он эффективен.

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

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

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

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

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

ответил Michael Kay 10 J000000Tuesday18 2018, 22:58:59
1

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

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

ответил user1118321 6 J000000Friday18 2018, 05:32:54
1

С написанием кода - как и при написании в целом - главный вопрос:

  

Какой читатель вы имеете в виду? или Кто потребляет ваш код?

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

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

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

Я думаю, вам не нужны ООП или модульные тесты для файлов с 150 LOC. Специальный VCS будет интересен, если у вас есть какой-то эволюционирующий код. В противном случае используется .bak. Эти инструменты - лекарство от болезни, возможно, у вас даже нет.

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

ответил Thomas Junk 7 J000000Saturday18 2018, 11:08:11

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132