пятница, 12 июня 2015 г.

Синдром “придумано не нами”

Ваш код сегодняшний, коллега
Напоминает даунхил:
Среди деревьев и гов#@ща –
Велосипед и костыли ...
Народная мудрость

Пару лет назад я сделал небольшой цикл заметок о паттернах поведения: Технический долг, Синдром рефакторинга и Эффект второй системы. Пришло время обсудить еще один, наверное, самый известный и популярный паттерн поведения – синдром «Придумано не нами» (NIH, Not Invented Here).

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

У «забить на существующее и сделать по-своему» есть несколько причин.

Во-первых, разработка с нуля – это lot of fun! Сделать свою конкурентную коллекцию, собственный менеджер по обмену сообщениями, или собственный ORM, - это же интересно! Это действительно классный способ узнать что-то более детально. Вот, правда, поддерживать чужие творения подобного рода – удовольствие ниже среднего.

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

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

В-четвертых, ты можешь думать, что у тебя получиться лучше. Никто не может написать нормальную библиотеку конкурентных коллекций, а ты сможешь. Никто не может реализовать свой собственный Key-Value Store, но только не ты! Тут есть два варианта: ты изучил разные реализации, и четко понимаешь, в чем у них проблемы и как от них избавиться. В этом случае ты просто не берешь в новое решение весь багаж накопленных ошибок из старых решений, а начинаешь с чистого листа. Ты не используешь готовый код, но точно используешь накопленный тобой и другими опыт. В итоге может получиться что-то хорошее, полезное и для тебя, и для других (Roslyn – отличный пример такого подхода).

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

Повторное использование vs. Изобретение велосипеда – это типовой компромисс, на который идут индивидуальные разработчики, команды разработчиков и целые компании. В Microsoft есть 4 разных системы для сбора и анализа телеметрических данных, десяток клонов анализаторов IL-кода и сотни или даже тысячи реализации коллекций всех мастей. И так в любой компании.

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

Распространение NuGet-ов и других менеджеров пакетов упрощают потребление сторонних компонентов и делают полезное дело в плане повторного использования. Но это интересное сочетание программистского пессимизма («все делают всё плохо») и оптимизма («но я сделаю всё хорошо»), никогда не убъет синдром “Not Invented Here” полностью. Что, может быть, не так и плохо;)

10 комментариев:

  1. Синдром, собственно, в чём заключается? В нелюбви чужого кода? Или во "всё выкинуть и переписать"?

    ОтветитьУдалить
    Ответы
    1. Во "всё выкинуть и переписать". Нелюбовь к чужому коду - это одна из причин, почему такой подход столь популярен.

      Удалить
    2. Понял, спасибо. У меня с этим другая боль: смотрю вокруг, и там, где мне кажется, нужно взять готовое - там пишется своё, а там, где наша просто самим всё выписать - берётся что-то и обкладывается костылями. 😞 То есть проблема не в чужом коде, а в том, как он используется (или не используется).

      Удалить
    3. Зачастую это любовь к написанию своих велосипедов как раз приводит к тому, что появляются отличные новые библиотеки и фреймворки. Если бы все использовали только чужие наработки прогресс в ИТ остановился бы, разве не так?

      Удалить
    4. Ну, ИМХО, все ж ведь несколько сложнее.
      Когда начинает писать свое собственное волшебное творение человек, без соответствующего бэкграунда и опыта написания чего-то подобного, то очень редко получается что-то хорошее.

      Когда Линус брался за Git он четко знал, что ему нужно, и как это можно сделать. Но если я бы взялся сделать что-то такое же, то результат был бы несколько иным...

      Речь об отсутствии крайностей, только и всего.

      Удалить
    5. А не случалось с вами так, что смотря на код, появлялось огромное желание переписать все это, а потом, из за интереса, посмотрев по history, мы обнаруживаи, что это наше творение, давности пару лет? Так, что причинами синдрома рефакторинга или эффект второй системы зачастую не только субъективны но могут быть и объективны. И в это есть рациональное зерно, это индикатор, что ты професионально рос.

      Удалить
    6. @Hamlet: да, если ты все еще гордишься кодом многолетней давности, то тут есть два варианта: код нереально хорош или ты перестал развиваться.

      Удалить
  2. В синдроме NIH надо учитывать и другую сторону! Например, почему если коллекция уже написана, то делал это опытный зубр, а не студентик-индус за день до сдачи проекта? Где "штамп качества"? :) Или вот готовый класс есть, но такой "развесистый всемогутер", что его использование превращается в гемор уже на стадии чтения примеров.
    NIH - это не только синдром личных амбиций, но и показатель качества существующего кода. ХОРОШИЙ код никто даже не подумает переписывать. Если код - говно, у него тут же находятся десятки клонов и новых версий.

    ОтветитьУдалить
    Ответы
    1. Штамп качества обычно идет рядом с самой библиотекой. Например, если что-то есть в BCL, то это говорит об определенном уровне качесвта. Но это, например, не касается NPM библиотек, которые вполне могут тримать строку и больше ничего.

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

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

      Удалить