MCP

четверг, 31 декабря 2015 г.

Про велосипеды

Несмотря на то, что сегодня 31-е декабря, хочется написать не праздничный, а технический пост. Хотя и философский слегка. Как же без этого. 

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

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

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

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

В общем, что я хочу сказать — внешние библиотеки могут приводить к куче отложенных проблем, к вендор.локу, когда она ироникают во весь код и избавиться от данной реализации уже невозможно без полного переписывания и прочим неприятным проблемам. При этом, все могут героически с этим бороться или вообще не считают проблемой. В тоже время считать, что своё решение хуже и каждый раз спрашивать: А может стоило использовать технологию X? Может и стоило... а может и нет, ведь сейчас ты пытаешься решить незначительную проблему, от которой будут счастливы пользователи, а на технологии  X проблему в принципе не решить, ок, все-лишь менее счастливые пользователи, мир не перевернулся.

4 комментария:

  1. Истина всегда где-то рядом. Я, наверное, умеренный велосипедист :)

    ОтветитьУдалить
    Ответы
    1. Хмм... хорошая градация. Велосипедист-ортодокс, велосипедист-light и все промежуточные стадии. Надо будет обдумать :)

      Удалить
  2. Макс, велосипеды - это да жаркая тема (я даже когда-то про это тоже писал https://outcoldman.com/ru/archive/2010/07/27/компоненты-написать-купить-или-скачать-/, даже не помню уже что там, не думаю, что буду может и согласен с тем, что написано)

    Хочу добавить немного случаев замеченных.

    В Microsoft я в MSBuild находил 3 или 4 реализации Task, который делает Zip пакеты. В Amazon существует правило, что только после того, как какая-то реализация будет написана 3-мя командами (точно число не помню) - необходимо будет выносить это как отдельный модуль (как они решают, какую реализацию брать - я точно не знаю). Со стороны может показаться дикостью, и хочется назвать всех быдлокодерами тупорылыми. Но все выглядит по другому, когда работаешь в этих командах. Скажем мой случай (он придуманный, но очень схож с реальностью) я работаю в diagnostics tools и мне нужно создать Zip архив, я смотрю в код MsBuild и нахожу одну реализацию, написанную командой UML диаграмм, там практически все подходит, но есть пару моментов, которые нужно исправить. Я пишу UML команде, попрошу добавить пару методов, они отвечают, что заняты чем-то, ресурсов нет, pull request принять займет тоже много времени, в твой бранч ХЗ когда дойдет, поддерживать это дело не будут, могут сломать в будущем, в общем тяжко. Я пишу MsBuild команде и спрашиваю, что не могли бы они взять этот компонент и начать его официально поддерживать. Они отвечают, что с удовольствием, что выпустят в версии vNext. А тебе нужно сейчас. Какой вариант выберешь - правильно, тупо напишешь сам. В общем я в этом случае просто хочу сказать, что в таким большим компаниях, когда работаешь над Diagnostic Tools, ты точно не хочешь брать ответственность над поддержкой какого-то компонента, вроде MSBuild Task который делать Zip пакеты, так как количество запросов что-то добавить, что-то сломалось - будет огромное. Если, когда-то поддерживал популярный open source проект, то, скорее всего, знаешь о чем речь.

    Еще по этой теме хотелось бы упомянуть тему микросервисов. После того, как я пересел с Windows на *nix мир, то все стало светлее в этом плане. Количество написанного добра на github превышает возможные ожидания. Очень легко найти что-то, что нужно, написанное на go или nodejs или ruby или еще чем-то, а еще завернутое в docker container, поднимаешь, настраиваешь и забываешь. Когда ты ограничиваешь себя только одной платформой / языком, то тут все не так радостно.

    ОтветитьУдалить
  3. А как назвать такое - взял готовую библиотеку, установил в проект через nuget, работает нормально, но память течет, за месяц примерно до гига на сервере приложений, на моем рабочем буке вроде и не течет. Сделал анализ дампа в windbg, нашел косвенные подтверждения того, что течет сериализатор, написал простыню на гитхаб - ответили "переопредели вот этот класс, замени protobuf на json и все будет норм". Заменить смог только на библиотечныый вариант, т.к. родной DataContractJsonSerializer сходу не смог подружить со строками для перечислений. Память как текла, так и течет. Психанул, скачал исходники, вырезал нахрен protobuf, вырезал нахрен ненужную мне COM-visible, сделал рефакторинг, вырезав ненужные вложенные классы и интерфейсы - перелопатил 200тыс. строк только сгенерированного для protobuf кода. Сумел подружить перечисления с родным сериализатором, вырезал стороннюю библиотеку. Память как текла, так и течет. Скопировал код подписывания (crypt32, все указатели запиненны в GCHandle) - вот где течет, да еще как течет. Сделал рефакторинг, все что мог вынес в конструктор класса, чтобы не создавать лишних указателей - нагрузочный тест теперь дышит ровно на нескольких кругах, проблему очертил. Завтра буду все собирать в рабочий проект, скорее всего еще помечу ненужные мне контракты (точь-в-точь с 1 картинки) и закомментирую.
    Это не велосипедирование, это что-то другое...

    ОтветитьУдалить