Я всю жизнь занимался исследованиями, поэтому знаю стереотип, что исследователи пишут уродливый код (например, см. здесь , здесь или здесь ). Но я подумал: мы можем это исправить, правда? Поэтому я несколько раз пытался разработать хорошие исследовательские рамки. Я пытался внедрить интерфейсы и создавать красивые абстракции, используя книги по разработке программного обеспечения и блоги, которые мне нравилось читать.
Но раз за разом все эти усилия оказывались напрасными. Большая часть исследовательского программного обеспечения, над которым я работал, так и не была запущена в производство (хотя некоторые из них так и поступили). Для моего психического здоровья было бы здорово, если бы кто-нибудь сказал мне простую истину: на самом деле должно произойти умирание исследовательского кода . Во-первых, исследователям не следует тратить много времени на его разработку.
Профессиональные инженеры-программисты всегда смотрят свысока на исследователей, которые не используют лучшие практики разработки программного обеспечения. Есть несколько постов, пытающихся поднять планку исследовательского кода (например, этот замечательный пост и руководство по исследовательскому коду ). Но этот пост говорит об обратном: он утверждает, как не переусердствовать с лучшими практиками разработки программного обеспечения и вместо этого инвестировать только в быстрое исследование. Он предназначен для исследовательских компаний, где ваша цель — быстро опробовать множество идей.
Успешный исследовательский проект компании состоит из двух этапов: разведка и эксплуатация. В «исследовании» вы хотите опробовать как можно больше разнообразных решений. В ходе «эксплуатации» вам необходимо усилить лучшее решение и превратить его в полезный продукт.
Оптимальные методы разработки программного обеспечения в этих двух случаях сильно различаются. Вот почему компании часто имеют отдельные исследовательские и продуктовые подразделения. Все книги, которые вы обычно читаете по проектированию программного обеспечения, в основном посвящены второй фазе «эксплуатации». На этом этапе вы создаете основу для масштабируемого продукта. Здесь на помощь приходят все шаблоны проектирования: хорошие API, ведение журналов, обработка ошибок и так далее.
Но на первом этапе «исследований» вы не строите фундамент, который будет жить вечно. Фактически, если большая часть ваших усилий сохраняется, значит, вы (по определению) недостаточно исследовали.
Многие практики в этой статье являются примерами того, что обычно называют «техническим долгом». Это то, что вы получаете, если не пишете чистый, хорошо абстрактный код, пригодный для многократного использования. Всегда ли долг – это плохо? Мы предпочитаем никогда не получать кредит или ипотеку, но заимствование денег часто является хорошей стратегией в жизни. Это нормально — влезать в долги, чтобы двигаться быстро и получить прибыль позже.
Точно так же, не принимая технический долг, вы можете замедлить свои исследования. Хорошей новостью является то, что в большинстве случаев вам не придется возвращать долг. Большая часть вашего исследовательского кода, скорее всего, умрет в любом случае. Таким образом, в среднем вы не будете страдать от всего полученного вами технического долга.
Многие архитектуры программного обеспечения и методы рефакторинга специально ориентированы на улучшение возможности повторного использования кода. Повторное использование кода имеет общие недостатки . Но в производстве их перевешивают известные преимущества (см., например, этот типичный пост ). В исследовательских проектах большая часть кода обречена на забвение. Стремление к повторному использованию кода может фактически замедлить вашу работу.
Ограничение повторного использования кода — это тот тип технического долга, который можно учитывать в исследованиях. Есть несколько моделей повторного использования кода, которые я хочу обсудить: добавление ненужной зависимости, копирование кода, сохранение большого количества общего исследовательского кода, преждевременные инвестиции в дизайн.
Если вы знаете хорошо поддерживаемую библиотеку с поддержкой версий, которая ускорит вас — дерзайте! Но прежде чем принять новую зависимость, попытайтесь принять решение, стоит ли оно того. Каждый дополнительный приближает вас к аду зависимости. Это заставляет вас тратить время на изучение и устранение неполадок. Дополнительные подводные камни зависимостей смотрите в этом кратком посте .
Наверное, хорошо от чего-то зависеть, если:
Но будьте осторожны с зависимостью, если:
вы не можете быстро разобраться, как им пользоваться, он очень новый (или очень старый) или о нем, похоже, никто не знает; нет никаких документов или тестов
он из вашего монорепозитория и постоянно меняется другими командами.
он использует множество других зависимостей и инструментов; или его просто сложно установить
и, наконец, вы чувствуете, что вы (или какой-нибудь LLM) можете написать этот код за несколько часов.
Вместо явной зависимости вы можете следовать хорошей поговорке Go: « Немного копирования лучше, чем небольшая зависимость », и это наша следующая тема.
Некоторые говорят, что « копипаст должен быть незаконным ». Но, к моему удивлению, я довольно часто приводил доводы в пользу этого. Копипаст может быть оптимальным выбором на этапе исследования.
Если вы зависите от часто используемой функции из другой части кодовой базы, вы можете забыть о ее легком изменении. Вероятно, вы кому-то что-то сломаете и вам придется потратить драгоценное время на обзоры кода и исправления. Но если вы скопируете необходимый код в свою папку, вы вольны делать с ним все, что захотите. Это имеет большое значение для исследовательских проектов, где экспериментирование является скорее нормой, чем исключением. Особенно, если вы не уверены, что изменения будут полезны всем.
Я считаю, что кодовые базы глубокого обучения больше всего подходят для копирования. Обычно объем кода, необходимый для описания модели и ее обучения, не так уж и велик. Но в то же время это может быть очень тонким и трудным для обобщения. Сценарии обучения, которыми можно делиться, имеют тенденцию разрастаться до неуправляемых размеров: например, тренер transformers
Hugging Face имеет +4 тыс. строк. Интересно, что трансформеры выбрали копипасту на уровне модели. Пожалуйста, ознакомьтесь с их сообщением с обоснованием их политики «однофайловой модели». Дополнительные ресурсы о красоте копипаста смотрите в конце.
Альтернатива копипасту — оставаться на ветке. Но мне кажется, что это приносит слишком много накладных расходов в командной работе. Также я нашел еще несколько постов о красоте копипаста — больше постов смотрите в заключении.
Обслуживание часто используемого общего кода требует большой работы. Взгляните на количество строк файла torch.nn.Module
, сопоставленное с версией Pytorch
. Вы можете видеть, что даже самые продвинутые исследовательские группы изо всех сил пытаются держать сложность под контролем.
Не стоит недооценивать время и ресурсы, необходимые для поддержки большого общего исследовательского кода. Чем больше используется научная библиотека, тем сложнее она становится. Это происходит быстрее, чем в обычной библиотеке, потому что каждое направление исследований имеет немного разные варианты использования. Установите очень строгие правила относительно того, что можно вернуть. В противном случае общий код станет хрупким и зарастет множеством опций, ошибочными оптимизациями и крайними случаями. Поскольку большая часть исследовательского кода вымирает, вся эта дополнительная сложность никогда больше не будет использоваться. Удаление части вашего общего кода высвободит некоторое время для проведения реальных исследований.
В некоторой степени это правда, что вы не хотите слишком сильно готовить свой код к будущему даже в рабочей среде. Постарайтесь реализовать максимально простое решение, соответствующее требованиям. Но в рабочем коде всегда необходимо учитывать аспекты удобства сопровождения. Например, вам обычно нужно думать об обработке ошибок, скорости, журналировании, модульности.
В исследовательском коде все это не имеет значения. Вы просто хотите как можно быстрее доказать, хорошая или плохая идея, и двигаться дальше. Так что грязная простота, которая достигается без каких-либо модулей или API, вполне нормальна!
Не тратьте драгоценное время на преждевременные инвестиции в программное обеспечение, такие как:
Цель исследовательского проекта – найти новое решение. Никто не знает (по определению), как это выглядит. Это похоже на процесс оптимизации в сложной исследовательской среде с ограниченной информацией. Чтобы найти хороший минимум, нужно перепробовать множество путей, распознать хорошие и плохие пути и не застрять в локальных минимумах. Чтобы сделать все это быстро, иногда вам нужно инвестировать в программное обеспечение вместо того, чтобы брать технологические долги.
Есть несколько различных направлений исследований, которые вы хотите попробовать. Есть ли дизайн, библиотека или оптимизация, которая сэкономит время на большинстве путей? Вы должны быть осторожны, чтобы не переусердствовать, потому что вы не всегда знаете все идеи, которые собираетесь реализовать. Это очень индивидуально для каждого проекта, но вот несколько примеров:
Исследователи должны иметь возможность быстро выдвигать новые разнообразные идеи. В начале проекта это кажется простым. Но затем постепенно становится все труднее и труднее, поскольку люди укореняются в своих любимых исследовательских путях. Для решения этой проблемы необходимы культурные и организационные изменения. Должен быть установлен процесс прекращения бесперспективных исследований, прежде чем вкладывать в них слишком много денег и эмоций. Регулярные демонстрационные дни и технические экспертные оценки могут служить эффективной стратегией для этой цели. Также важно найти баланс между людьми, которые ухватываются за новую блестящую идею и должным образом закрывают текущие проекты.
Но это статья о программном обеспечении, поэтому вот несколько приемов, которые облегчат создание новых проектов:
Шумный код с ошибками делает результаты настолько неоднозначными и неубедительными, что весь проект становится пустой тратой времени. Хотя вам не следует переусердствовать с проектированием, вы можете легко следовать этим простым практическим правилам, чтобы избежать беспорядка в коде:
избегайте кода с побочными эффектами
по умолчанию используются функции, а не классы; а с классами предпочитайте инкапсуляцию, а не наследование.
минимизировать длину функций/классов/модулей; минимизировать количество операторов if
хорошо знать Python, но использовать простые методы. Не поддавайтесь искушению углубляться в интеллектуальные сорняки метаклассов, декораторов и функционального программирования.
С программным обеспечением, которое дает разные результаты при разных запусках, работать сложно. Если вы приняли важное, но неправильное решение, основанное на неудачном семени, вы потратите много времени на восстановление. Вот несколько советов при работе с недетерминированным программным обеспечением:
Изюминка взята из этого поста об исследовательском коде:
«Вы не беспокоитесь о [хорошем дизайне программного обеспечения], потому что код не имеет значения. Код — это инструмент, который дает вам ответ, который вам нужен» .
Чрезвычайно важно иметь хорошую основу для кодирования. Но, в конце концов, главное — это исследование и действительно полезный продукт. Если вы используете слишком много производственного программного обеспечения в исследованиях, вы теряете время, необходимое для открытия чего-то нового. Вместо этого найдите то, что замедляет ваш процесс исследования. Ускорьте исследования, инвестируя в быстрое ветвление, сокращение времени получения результатов и чистый бесшумный код.
Было бы безумием полностью выступать против повторного использования кода. Я просто хочу отметить, что повторное использование кода должно быть хорошо сбалансированным занятием. В исследованиях доля выбрасываемого кода больше, чем в производстве. Баланс еще больше склоняется против повторного использования. Вот еще несколько отличных постов с подводными камнями повторного использования кода:
И вот еще несколько постов, в которых аргументируется практика копипаста:
Спасибо за чтение! Я чувствую, что некоторые моменты немного спорны, пожалуйста, дайте мне знать в комментариях!
Также появляется здесь .