Как стать автором
Обновить

Комментарии 34

мой первый язык....эх вспоминаю ночи которые провел за книгой

Я тоже на нем кодил немножко.

Мой первый язык программирования) Там много было интересных подходов, которые перетекли в другие языки. Жаль Perl 6 убил развитие Perl 5, на котором все писали...

До сих пор пишу на нём клей и прототипы и скрипты, Python не знаю, стимула переходить на Python как-то особо и нет. ООП/ФП нет, язык напрочь императивный, но дело делает лучше шелла.

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

Почему же нет ООП, из коробки можно конструировать классы. Плюс есть Moose, ещё мощнее штука.

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

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

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

ИМХО на Perl можно делать склейки (как на bash или python), делать минимальные обвязки. Но делать на нем большие проекты категорически противопоказано.

старый вариант стало вообще невозможно поддерживать из-за каши, макарон и write-only языка

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

Тем не менее, репутация языка, на котором пишут write-only code, именно у Perl появилась видимо не просто так.

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

Кстати, писал он на Паскале.

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

Простите, у кого не течет память? У perl? Вы писали на Perl что-то сложнее hello world? Он жрет как не в себя, при этом НЕ отдавая память обратно в систему считая, что она пригодится в будущем. У Perl есть критический недостаток в отсутствии изкоробочных threads, (зачатки которых появились в 2.27, что выше чем та версия, на которую всё было завязано) из-за чего просто пропинговать ряд устройств занимало 25 секунд из-за того, что многопоток был недоступен. Fork дублировал всю память, которую perl нажирал из-за Mojo, MySQL и тонны других библиотек. В итоге обычный пингер который пишет результат в базу работал 25 секунд и жрал 100+ метров. Сишный аналог выполняется за 2 секунды и ест на уровне погрешности дефолтного аллокейта стека.

Но через какое-то время при таком подходе вы накопите спагетти и в C (кстати, странный выбор для веб-приложений, вы б еще на ассемблере писали).

в C за ней самому следить надо) и с Segmentation Fault не падало.

У вас нет нужной компетенции в С чтобы так говорить. Правильно написанный код не падает с SegFault и при его написании никак не мешает использовать освобождение памяти. Наш код проверяется статическими и динамическими анализаторами, часть из которых встроена в автоматический CI/CD.

кстати, странный выбор для веб-приложений, вы б еще на ассемблере писали

На ассемблере у нас подсчет хешей. А веб приложения по причине ограниченной памяти на конечных узлах. Поверьте, то что это С никак не влияет на скорость разработки, мы API планируем дольше чем его пишем. Любой другой бекенд будет жрать больше, чем там есть памяти в 10 раз. У нас есть другой бек на Scala, который именно такие аппетиты и имеет.

    g_server_instance = fen_server_create(
        pls_port_webgui,
        NULL
    );

<...>

    fen_handler_add(
        g_server_instance,
        NULL,
        NULL,
        edd_request_process
    );

<...>

for (i = 0; i < BXI_ARRAY_SIZE(requestables); i++) {
        if (bxi_strcmp(path_relative, requestables[i].resource) == 0) {
            edd_resource_add(
                requestables[i].method,
                requestables[i].uri,
                (const char *)file->data,
                file->size,
                requestables[i].json,
                NULL
            );
            frs_inf(" + \"%s\"", path_relative);

            added = true;
        }
    }

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

У вас нет нужной компетенции в С чтобы так говорить.

Вы со мной знакомы чтобы это утверждать?

Я это понял по вашим заявлениям про сегфолты и тродности написания кода. Это стереотип.

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

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


Правда, у меня опыт плюсовый.


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

Из какого списка, если вы добавляете только path_relative, который внутри цикла не меняется? По крайней мере, я надеюсь, что не меняется, но в C и C++ никогда в этом нельзя быть уверенным без взгляда на кишки bxi_strcmp.


Кстати, ради интереса, а сколько обычно записей в requestables?


Как мне, глядя только на edd_resource_add, понять, какие аргументы вообще могут быть NULL?


Как мне понять, передаётся владение у третьего параметра или нет, и что с ним вообще происходит? Могу ли я закрывать файл после edd_resource_add?


Ну это так, просто вопросы сходу.

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

На эти вопросы есть ответы в документации к функциям.

Документация не проверяется компилятором.


Записей может быть сколь угодно много.

Точно ли тогда O(n)-скан списка оптимален? Не лучше ли сформировать хеш path_relativerequestable? Насколько быстро вам в C будет проверить эту гипотезу?


файл закрывать можно, библиотека сделает копию

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

Документация не проверяется компилятором.

Несоответствие входящих типов проверится компилятором + рантайм анализаторами (valgrind, memcheck) + адекватностью работы (тестирование важно, да. Даже если для него нужно написать отдельный сервис-эмулятор). Ну и PR-Review

Точно ли тогда O(n)-скан списка оптимален?

А там просто рекурсивный проход по директории - защита от взлома путем подстановки путей типа "../../../passwd" - если есть только readonly список доступных ресурсов, сформированный на этапе компиляции\инициализации, то система более надежна. Функционал сервисов, что мы запускаем обычно укладывается в несколько страниц html (формируемых по шаблону и данных), c полдесятка *.css, и такого же количества *.js. Плюс картинки, плюс шрифты и проч. Нет смысла особо оптимизировать проход по списку, когда он выполняется за <10 ms.

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

Памяти мало, но не настолько. Последний такой сервис поднимали для 2GB Raspberry, потребление не превышает 3 MB + сумма размеров отдаваемых ресурсов (храним в памяти чтобы не тыкать лишний раз SD).

Как это сделать в вашем фреймворке?

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

Несоответствие входящих типов проверится компилятором

null где не надо компилятор не найдёт. Перепутанный method и uri тоже, тащем.


рантайм анализаторами (valgrind, memcheck)

Если вы способны дождаться завершения работы кода под valgrind, то вам ещё повезло. Если баги не плавающие и не пропадают под valgrind (asan, etc) — повезло вдвойне.


Плюс, рантайм-анализаторы не способны гарантировать отсутствие багов. В отличие от типов.


  • адекватностью работы (тестирование важно, да. Даже если для него нужно написать отдельный сервис-эмулятор). Ну и PR-Review

И всё это — лишь бы не писать на нормально типизированных языках.


А там просто рекурсивный проход по директории — защита от взлома путем подстановки путей типа "../../../passwd" — если есть только readonly список доступных ресурсов, сформированный на этапе компиляции\инициализации, то система более надежна.

Не понял связи с защитой от взлома, ну да ладно, видимо, это слишком контекстно-зависимо.


Эх, был бы какой-то способ выразить в типах отсутствие относительных путей, например…


Нет смысла особо оптимизировать проход по списку, когда он выполняется за <10 ms.

Чтобы под валгриндом сэкономить уже секунду :]


Памяти мало, но не настолько. Последний такой сервис поднимали для 2GB Raspberry, потребление не превышает 3 MB + сумма размеров отдаваемых ресурсов (храним в памяти чтобы не тыкать лишний раз SD).

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


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

А прикиньте, как было бы здорово, если бы там как-нибудь сами учитывались времена жизни либо рефкаунт какой-нибудь хотя бы?

И всё это — лишь бы не писать на нормально типизированных языках.

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

Плюс у вас страничка работать не будет, если вы перепутаете method и uri, первое же тестирование и придет тестировщик и побьет вас палкой.

Если вы способны дождаться завершения работы кода под valgrind, то вам ещё повезло.

Мы разбиваем большие демоны на микросервисы, поэтому проблем с долгой отладкой обычно нет. Например перенастройка сетевых настроек на узле состоит из трех демонов - веб-интерфейса который умеет отдавать странички с POST-формами для изменения, демона который такие запросы обрабатывает и умеет менять сетевые конфиги и демон, который умеет детектировать провалы тоннеля и отдавать данные во второй, чтобы тот, например, перезагрузил тоннель. Из-за того, что по факту изменения применяет ровно одна точка - то есть адекватный lock/unlock а cloc при этом 1400, 1100, 400 соответственно (без учета библиотек).

А прикиньте, как было бы здорово, если бы там как-нибудь сами учитывались времена жизни либо рефкаунт какой-нибудь хотя бы?

У нас есть библиотека для подсчета ссылок, кое-где используется :D

Так вам никто не мешает сгенерировать типов через typedef чтобы анализаторы заметили несоответствие.

Это какой анализатор показывает несоответствие между myint и int для


typedef int myint;

?


Я уж не говорю о том, что через тайпдефы всё не выразишь.


Плюс у вас страничка работать не будет, если вы перепутаете method и uri, первое же тестирование и придет тестировщик и побьет вас палкой.

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

Между myint и int не покажет, но если делать struct, то даже дефолтные опции сборки скажут "Форзихт!": https://onlinegdb.com/5n3Sbk5hy

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

Ну так struct — это не typedef, это вы не можете написать MyInt s1, s2; s3 = s1 + s2;, потому что у вас больше плюсика нет. Это не C++, где есть хотя бы перегрузка операторов, и уж тем более не хаскель, где можно просто написать


newtype MyInt = MyInt Int deriving (Eq, Ord, Hashable, Num, Integral, ...)

но это вообще не самая популярная ошибка

Кстати, чисто из интереса — что вы бы у себя назвали популярными ошибками?


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

Ну так :]

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

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

Впрочем, у меня, как у эмбедера, кроме сей и выбора-то никакого нет.

Наверное при переходе с Perl на C вам и команду программистов пришлось менять?
Или перловиков переучивали?

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

Участвовал в миграции проекта на Perl с историей в 15 лет на NodeJS/TypeScript. Это был проект одного из крупнейших ВУЗов страны, он состоял из сайта, мобильного приложения и админки.

Причины переписать были следующие:

  • Перловых разработчиков мало и хорошие стоят прям очень дорого, а джуны не рвутся поднимать скилл в Perl

  • Типизация TypeScript здорово облегчает работу с большой кодовой базой, а один язык и на бэке, и фронте, чуть облегчает переключение контекста.

  • Асинхронность в Node js в из коробки. А в perl есть решения типа AnyEvent, но они проигрывают по степени удобства и надежности работы языкам, у которых асинхронность базовая фича

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

  • Из-за того что мы были прибиты к apache и mod_perl, отсюда вытекали все классические проблемы с обслуживанием большого кол-ва запросов.

Исходя из вышеперечисленного переписать на другой язык, казалось не такой плохой идеи. Плюс мы хотели разбить монолит на 2-3 сервиса поэтому переезжали постепенно. NodeJS убрала проблему избытка потребления памяти, а за счет снижения кол-ва подключений к БД мы даже смогли убрать pgbouncer и кэш виде Redis.

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

Слышал что хорошие специалисты по NodeJS тоже очень дорого стоят, не дешевле перловиков. Мы вот кстати, сами перловиков обучаем, если кому нужны - обучим под ваши требования.

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

Это дас) Вообще хорошие разработчики дорого стоят, но если в NodeJS нет проблем с junior и middle, то в Perl остались только сеньор за которых надо еще конкурировать с Mail, Yandex и другими большими компаниями, где еще осталось много перла. Ну, и физически сеньоров на Perl меньше, чем на Node, многие ушли в Си++, Gо, Python и ту же Node. По крайне мере у нас был такой опыт поиска ...

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

сеньоров на Perl меньше, чем на Node

Это да, поэтому новичков обучаем Перлу сами. Реально нам удается найти достаточное количество кандидатов. Но переезд нашего сервиса на Node - нереально дорого, проще уж своих перловиков подготовить)

Очень интересно. Спасибо.

Пожалуйста

был абсолютным гуманитарием.

Наверное, поэтому Уолл поступил в Тихоокеанский университет Сиэтла на специальность «химия»

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

Честно говоря, 9 лет, проведенные мной на Перле, считаю убитым временем.

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