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


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


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


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


Рассмотрим несколько случаев.


image
Источник


API над API


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


Случай из моей практики.


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


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


Результат: через 1.5 часа работы с ней, не удалось даже авторизоваться.


Коллега реализовал собственную обертку web-api фейсбука. Суммарно, на создание обертки и связанной функциональности на стороне сервиса у него ушло около часа. На вопрос "а зачем ты тут навелосипедил", он отвечал следующие несколько дней.


Подобное особенно ярко проявляется в мейнстримовых язык с большим коммьюнити: появляется нездоровая тенденция публиковать обертки API над другим API, под лозунгами "For humans" и "In simple way". Такие обертки устаревают, как только оборачиваемый интерфейс обновляется, а авторы забрасывают такие "проекты", делая код, их использующий, нерабочим.


Здравый вопрос: и что, каждый раз писать такие обертки вручную?


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


Контроль над кодовой базой и отказ отвечать за чужие ошибки


В кругах wannabe разработки компьютерных игр такая фраза адресуется любому, кто посмеет реализовать свой движок. "Зачем изобретать велосипед? Возьми юнити!". Или Game Maker, или, не, дай бог, Defold.


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


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


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


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


Например, исходя из подобных посылок Томми Рефенес написал свой движок для Super Meat Boy.


Кто-то возразит: "Но ведь в сторе\еще каком-то хранилище, есть же гора пресетов\инструментов\расширений!".


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


Мнимая идентичность. Притягивание задачи за уши.


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


Хороший пример: CluNet.


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


Вывод


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


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


Или, по-капитански обобщая:


Прежде, чем решать — думай.
Прежде, чем говорить — думай.
И вообще — думай.

Комментарии (32)


  1. Heian
    06.05.2019 22:44
    +2

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

    P.S. Сам плевался от фейсбучных SDK, в итоге написал за полчаса коннектор на curl.


  1. Cerberuser
    07.05.2019 04:28

    Пилим большой (относительно — бандл около пяти мегабайт в сумме) проект на React и TypeScript. Периодически сталкиваюсь с тем, что существует почти подходящее решение где-то в недрах npm, но в нём есть досадное несоответствие нашим ожиданиям, из-за которого брать эту библиотеку к себе "как есть" — значит, наворачивать вокруг неё лютые костыли. Уже несколько раз форкал такие пакеты и тащил в проект собственную версию. Тоже своего рода велосипед (пусть и по большей части из фабричных деталей)? Зато руль ровно нужной высоты и тормоза откалиброваны.


  1. VolCh
    07.05.2019 07:30

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


    С другой стороны, налицо фактор протекания, просачивания не используемых сначала функций больших библиотек, затянутых в проект ради одной, в результате чего заменить её на практике почти невозможно. Хрестоматийный пример в веб-разработке — jQuery. Затащили ради AJAX или промисов, а потом во всем приложении используется всё, да ещё jQuery UI. Основной аргумент — уже есть же, не надо новую зависимость, не надо велосипед писать…


    1. 0x1000000
      07.05.2019 08:29

      И аргументы должны быть чёткими, чтобы два дня не объяснять

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


      1. VolCh
        07.05.2019 09:15

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


        1. RoSenMann Автор
          07.05.2019 09:21

          Нет, его просто в течении нескольких дней спрашивал каждый встречный.


          1. Newbilius
            07.05.2019 12:26

            Но ведь в самом вопросе ничего странного нет :) Видишь контринтуитивное решение — спроси коллегу, почему он его принял. И отсутствие готовой обёртки к популярному сервису действительно вызывает недоумение и недоверие. Мой опыт показывает, что такое бывает — но редко.


            1. RoSenMann Автор
              07.05.2019 12:34

              Про контринтуитивность — хорошее замечание.


            1. 0x1000000
              07.05.2019 15:36

              И отсутствие готовой обёртки к популярному сервису действительно вызывает недоумение и недоверие

              Вполне могу себе это представить. Обертка для Java, скорее всего, будет и будет актуальной, но ведь еще есть: .Net, Go, PHP, Ruby, Python и т.д. – поддерживать API обертки в актуальном состоянии для всех возможных языков и технологий может быть проблемой даже для очень крупной компании.
              Некоторые мысли про REST сервисы
              Эта проблема, на мой взгляд, проистекает из-за того, что у REST сервисов нет общепризнанного механизма их описания. Если бы он был (и все бы его использовали), то написать универсальные генераторы API оберток для всех актуальных платформ, не было бы проблемой.


              1. polar11beer
                07.05.2019 18:47

                Эта проблема, на мой взгляд, проистекает из-за того, что у REST сервисов нет общепризнанного механизма их описания

                Хм… Swagger a.k.a. OpenAPI?
                И кодогенерация под мейнстримовые языки в нём имеется.


                1. 0x1000000
                  07.05.2019 19:04

                  Когда (если) Swаgger станет стандартом (тут можно вспомнить про WADL), то да, проблема отпадет.


                  1. nrgian
                    07.05.2019 19:24

                    Когда (если) Swаgger станет стандартом

                    Он вполне себе стандарт-дефакто один из пары. Что переименованием только подчеркнуто.
                    Дело только в лени/нехватки времени программистов его использовать/изучать.


          1. VolCh
            07.05.2019 14:43

            Просто надо было написать это где-то, где все сами могли прочитать. например в комментарии к MR/PR. Или рассказать на дейли-митинге, груминге, планерке и т. п.


  1. synedra
    07.05.2019 09:14
    +1

    "Зачем изобретать велосипед? Возьми юнити!"

    У этого решения есть ещё один недостаток, который распространяется на многие не-писания-велосипедов. Юнити часто оверкилл и он может тащить непропорциональные системные требования. Они не запредельные, да, но всё равно как-то странно, когда рогалик с минимальной анимацией, не поддерживающий даже мышь (не говоря уже о геймпадах, 3D, VR и чёрте в ступе), весит 100+ Мб и лагает на интегрированной видеокарте. Серьёзно, отрисовка страниц в браузере — несопоставимо сложнее, чем весь UI игры, но как-то же фаерфокс умудряется работать на относительно старом железе.


    1. Newbilius
      07.05.2019 12:54

      Но есть другая проблема: если конкретный разрабочтик игры не смог на юнити оптимизировать рогалик с минимальной анимацией — разве можно надеяться, что он сможет написать с нуля игровой движок с лучшей производительностью? Автор игры скорее всего не осилил документацию по движку — но вот с нуля написать на SDL или вручную на OpenGL+DirectX он сможет написать нечто лучшее? Сомнительно :)


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


      1. poxvuibr
        07.05.2019 18:16
        +2

        Но есть другая проблема: если конкретный разрабочтик игры не смог на юнити оптимизировать рогалик с минимальной анимацией — разве можно надеяться, что он сможет написать с нуля игровой движок с лучшей производительностью?

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


  1. Pavenci
    07.05.2019 09:22

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

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


    1. VolCh
      07.05.2019 14:41

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

      Время и деньги на разработку, плюc, наверное главное, время и деньги на поддержку.


  1. AlexVist
    07.05.2019 09:37

    Приветствую! Хотелось бы дать небольшой комментарий. Любая проблема, как медаль, имеет две стороны. Так и аргументы высказанные в статье описывают лишь одну сторону медали. Спасибо за примеры из практики. Так, действительно, лучше разъяснять свою точку зрения.
    Существует и обратная сторона медали. Разработка своего в рамках решения задачи далеко не всегда есть велосипед. Вопрос заключается в том, учтен ли уже существующий опыт при решении подобных задач. Потому что изобретение велосипеда часто превращается в изобретение квадратного деревянного колеса.
    Часто разработчики мнят себя гениями и первооткрывателями. Но, согласитесь, что мы в средней массе не Моцарты, а, дай Бог, Сальери. Из этого следует, что выбор пути решения должен быть результатом изучения технологий и подбора правильного стратегического решения. Которое не приведет в дальнейшем к серьезным проблемам.
    Опыт и знания позволяют иногда выносить суждения о том, что не нужно изобретать велосипед. И все, далеко не ограничено выбором API, фреймворка или библиотеки. Естественно, что все выводы должны быть обоснованы. Но я, даже, предлагая уже известные и успешно реализуемые много лет концепции, сталкивался с непросветной глупостью "гениев изобретения велосипедов". Как результат в промышленной реализации возникали и продолжают возникать проблемы, которых легко можно было избежать.


    1. Whuthering
      07.05.2019 11:26

      Часто разработчики мнят себя гениями и первооткрывателями.

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


      1. AlexVist
        07.05.2019 11:43

        Да беда и в релевантности тоже. Если человек несколько лет изобретал в какой-то области квадратные колеса. То вот вам и специалист со стажем! Только качество стажа и кругозор у него слишком узки.


      1. RoSenMann Автор
        07.05.2019 12:26
        +1

        Потом он выкладывает свое решение на гитхаб, формирует пакет, рекомендует ее кому-то на StackOverflow и понеслась. Теперь его девиз «Не изобретай велосипед, возьми мой!» :)
        Посылку поддерживаю. Поэтому я и говорю о «нескольких минутах раздумья». В сущности, бездумно бросаться реализовывать так же безалаберно, как и бездумно втаскивать другие решения.


  1. virtualsys
    07.05.2019 10:28
    +1

    Самое важное при выборе — рассудительность. А рассудительность включает адекватную оценку своих целей, возможностей и рисков. Тут идет рассуждение на уровне кодера-разработчика.

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

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

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

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


  1. agalakhov
    07.05.2019 11:12
    +1

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


  1. ToSHiC
    07.05.2019 11:38

    Хороший пример: CluNet.

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


  1. Newbilius
    07.05.2019 12:44

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


    • хватает умений, чтобы не только написать всю игровую логику, но и игровой движок, причём делающий необходимый минимум функций не хуже или лучше готовых движков. Сюда может входить удобный редактор уровней, поддержка сразу нескольких игровых платформ (Windows/PS/Xbox), хорошая работа с разным оборудованием (вспоминаем те же геймпады) и многое другое
    • есть время, чтобы написать не только игру, но и движок, а так же в дальнейшем его поддерживать

    И на любой пример "автор написал свой движок и выпустил популярную игру" можно привести сотню "автор взял готовый движок и написал популярную игру". Блин, да даже Blizzard использовала Unity для Hearthstone, хотя вот у кого-кого, а у них недостатка в ресурсах уж точно нет.


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


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


    1. VolCh
      07.05.2019 14:50

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


  1. rombell
    07.05.2019 14:39

    Что касается использования игр на Unity — имею негативный опыт пользователя.
    Одна достаточно несложная, но увлекательная игра, в которую я постоянно донатил, была на Unity. После очередного обновления движка Unity он, а с ним и игра, перестал запускаться на относительно старых системах и относительно старых браузерах типа ФФ двухгодичной давности. Я решил, что эта игра не стоит обновления железа и системы. При этом сама игра от обновления не получила ничего, всё и так прекрасно работало (и, кстати, практически не развивалось — так что новые возможности движка не требовались, даже если они и были)


  1. i360u
    07.05.2019 15:05

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


  1. tmteam
    07.05.2019 16:05

    Да, черт побери — писать велосипеды это весело! (в начале)


  1. wladyspb
    07.05.2019 16:31

    С точки зрения получения ценного опыта — «каждый разработчик должен написать свой фреймворк». Не обязательно его при этом использовать) Я бы сказал, что для достаточной компетенции нужно написать свой фреймворк, и изучить пару тройку популярных.
    В целом, статью поддерживаю, очень часто приходится писать свои решения, а чужие, в случае когда принимается решение «не писать свой велосипед», иногда приносят много боли на этапе поддержки, или когда выясняется что для фичи, которая развивается, понадобился не только функционал «А», представленный в библиотеке, но и функционал «Б», который придумали уже после внедрения сторонней либы, и который в ней отсутствует.
    Впрочем, для наиболее распространённых задач, на популярных языках, как правило есть несколько десятков\сотен готовых решений, и достаточно найти в топе по скачиваниям на гитхабе такой вариант, который поддерживается мейнтейнерами. К сожалению, не все задачи, которые приходится решать, являются «распространёнными»)


  1. nrgian
    07.05.2019 17:29

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

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