Pull to refresh
3
2.1

Специалист по теории типов USB-кабелей

Send message

отвечать на одинаковые вопросы

Как вы могли устать отвечать, если ни единого ответа на это от вас не было?

при том, что оппонент полностью игнорирует аргументы

Как можно игнорировать то, чего нет?

этого кода в современном мире около 90%. вместо того чтобы тащить в мир типы, вы бы лучше придумали как эти 90% сократить хотя бы до 50.

Я вам снова на примере показал, как это количество сократить до round $ 1 / (1 + 12) = 8%, а вы снова это игнорируете.

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

Абсолютно верно. Бизнесу не нужны тесты и аджайл. Бизнесу нужен работающий код. Ваше слепое поклонение тестам совершенно необоснованно.

прочее скипну ибо повтор, устал

Что вы устали? Игнорировать эмпирические данные? Так вы и в прошлый раз это скипали и не отвечали по существу. Я вам пример, как разделение на чистые и нечистые функции не увеличивает объём кода, вы продолжаете бегать с «в два, нет, в три, нет, в десять раз больше пять экранов текста!»

затем, что этот код мы пишем? пишем.

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

прежде чем отдавать его клиентам убедиться нужно, что он работает? нужно

Карго-культ и секта.

Ну так см. последний абзац.

Или Data.String.Interpolate.

  • с debug-данными

  • с трейсом всех ошибок

  • с профайлом всех запросов по всему стеку

Чем меняют поведение наблюдаемой системы и её перф-характеристики.

Там, где я работал и где скорость ответа действительно была важна и приводила к более плачевным денежным исходам, чем «юзер монополиста подождёт вызова такси не 5 секун, а 10, и с вероятностью 1% в следующий раз предпочтёт идти пешком», это не работало. Работает только снятие полного дампа трафика и дальше уже существенно более тяжёлая артиллерия, чем дебаг-данные, трейсы ошибок и профайлинг средствами языка/окружения.

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

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

Так там нету.

вынуждены писать более сложный код

Что сложнее? Как раз проще: понятно, что может завершиться ошибкой (и какой), а что — нет.

от повышения сложности код становится менее надёжным, а не более, как хотелось бы

Бездоказательное утверждение.

а новых взамен не получили

Получили статические гарантии. Это лучше.

я пожаловался что с переходом на return error мы утратили весьма удобный инструмент

Только его и не было.

который помогал в отладке

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

Да не, снова ерунда.

вы НАМЕРЕННО задали вопрос из области "были примеры, где этот инструмент не работал".

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

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

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

Соответственно, законы физики и теории вычислимости не мешают тому же .NET CLR записывать трейс каждый раз, когда вы в F# возвращаете его аналог Left , или мне наваять за пару вечеров плагин к ghc, который каждой функции будет добавлять констрейнтHasCallStack , чтобы потом его захватывать в моей собственной иерархии ошибок.

Просто это всё нафиг никому не нужно, потому что ценность трейсов в сильно типизированных языках переоценена. Это как жаловаться, что JS безапелляционно лучше C++, потому что в JS есть eval.

Только при этом они есть даже в питоне. Просто спецификации формата — это, внезапно, спецификации формата, которые нужны, чтобы показать, условно, сколько знаков после запятой печатать, а не что-то там затыкать. Использование %d или %f в том же питоне — это просто дань традиции, чтобы программистам из других языков было проще и привычнее.

Нет никаких причин, почему нельзя было бы писать просто % в хаскельном printf — типы аргументов всё равно известны статически, и как их печатать, тоже известно статически. Просто WTF-момент от простых процентов больше, чем экономия пары знаков.

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

printf "Hello {}, your age is {}"

имел бы тип Show a ⇒ Show b ⇒ a → b → String , даже проще, чем париться с полноценным разбором строки форматирования в компилтайме и последующим тайпчекингом аргументов.

Я не понимаю, как вы можете это всерьёз писать после того, как вы сами попросили меня реализовать выбранную вами (и по-вашему грязную) функцию в ФП, я это успешно сделал, выделив одну строку на грязь и дюжину строк на чистоту (такое-то удвоение ×2), и в итоге всё равно всё занимало меньше, чем у вас в вашем языке.

размер кодовой базы от такого действия удвоится (а то и утроится) - что никому не нужно.

А чё не удесятерится? Откуда здесь хотя бы даже удвоение?

тестировать "грязные" всё равно придётся

Зачем?

Пат

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

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

то есть то, что в НЕКОТОРЫХ случаях работающий инструмент был не (совсем) применим

В каких «НЕКОТОРЫХ»? Это стандартный случай для работающего в проде (сиречь собранного с оптимизациями, и так далее) кода на C++.

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

В какую клетку, зачем загонять? Что это за фантазии проступают через текст?

просто сама пардигма с async/await ущербна, что поделать. есть лучшие парадигмы - stackful.

ИМХО количество мест, где stackless полезнее, особенно для уже имеющихся языков с имеющимися кодовыми базами, куда выше, чем где stackful полезнее.

в том и дело, что мне НЕ нужно собирать трейсы всегда и везде.

Ну так тем более, собирайте только там, где нужно. В чём вопрос-то?

Если откуда-то трейс не нужен — просто не записывайте его, точно так же, как вы сейчас его не записываете, если он вам не нужен.

интеграционный тест фиксирует внешнее поведение

  1. В одном конкретном случае из миллионов.

  2. На это надо потратить время, и ради чего?

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

прокликали - это и есть тесты. просто выполняете их вручную.

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

тесты решают реальные проблемы

Так какие проблемы они решают, кроме повышения зарплаты в потогонках через демонстрацию написанных строк кода, и прикрытия ЧСВ тимлидов, мастурбирующих на совершенно бессмсыленные метрики вроде code coverage?

Доказательством тому - статистика мест, где пользователи чаще делают ошибки.

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

В нормальном языке для начала было бы

add : (a b : Int) → {auto nonZero : b ≠ 0} → Int

потому что иначе тело бы не скомпилировалось, например. Опа, и у вас нет паник.

Потом вы бы попытались доказать какие-нибудь свойства этой функции, вроде add a (add b c) = add (add a b) c, и у вас бы это не получилось, и вы бы подумали, что add делает какую-то ерунду (и правда, делает ерунду). Опа, и у вас нет вранья в именах.

А в тестах без типов бы вы написали add (-4) 2 = -2 и пошли бы дальше писать микросервисы для кэширования, не заметив, что делаете ерунду.

А что с ним нетипизируемого? Даже хаскель может.

так вот, нормальные интеграционные тесты помогают в обоих случаях

Бездоказательное утверждение.

смоделировали действия пользователя в тесте - поправили. тест сохранился на будущее.

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

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

как-то так это и работает

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

Тесты не-ну-жны и вредны.

Так как вы сами писали, что не терпите бездоказательных утверждений, то я посчитаю их в этом комментарии ради лулзов:

затем, что это естественно для человека НЕ оперировать типами

1

И ему пофиг что считать. Типы становятся не важны.

2 [альтернатива: человек генерализирует до общего типа «считабельные объекты», а неспособные в генерализацию люди не осиливают счёт за пределами палочек]

аннотации нужны только компилятору

3

просишь ИИ переписать код без аннотаций в код с аннотациями и ИИ отлично с этим справляется

4

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

5

и рано или поздно так и будет

6

У Хаскеля проблема в том, что он уже 30 лет research language. С соответствующим культурным кодом. Хотя, как говорится, "вы 50 лет занимаетесь полупроводниками, пора бы уже к полным проводникам перейти!".

В OCaml хотя бы можно быть уверенным, что если написал программу на stdlib, то через 20 лет она будет почти полностью компилироваться на trunk.

Некоторая ОС с девизом stable API is nonsense вполне успешно живёт что на мобильниках, что на серверах, так что не думаю, что проблема именно в этом.

оно текст пока оно нужно как текст.

Оно нужно как текст только при записи в логи. Делать текст до этого не нужно совершенно.

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

И рантайм раскрутит обратно все заинлайненные функции, и соотнесёт точку создания экзепшона в асинхронщине со всеми точками запуска всех асинхронных вещей?

Магия! Очень здорово! Можете меня научить делать эту магию на C++? Вот я пишу где-то

try
{
  doStuff();
}
catch (const std::exception& e)
{
  // *
}

Что мне надо написать вместо звёздочки, чтобы получить вот это вот всё? doStuff не знает, что и где будет вызвано, и вообще это может быть в глубине корутин.

Я, кстати, как раз на днях дебажил крэш из-за того, что некоторый awaitable в await_suspend подписывается на событие (возобновляющее соответствующую корутину) и ожидает, что await_resume будет вызвано только тогда, когда это событие произойдёт (и корутина будет возобновлена «симметрично» этому await_suspend), а это не так. Получить адекватный стектрейс там невозможно даже в отладочной сборке из-под gdb, потому что всё падает, будучи вызванным сильно из другого места.

Как в этом случае поможет ваша магия? Куда нажать?

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

Он возвращает характерную для парсера ошибку. Нужен стектрейс — вызовите backtrace() (или как его там в расте) при обработке (которая может свестись к одному вызову higher-order function, типа withBacktrace(parse(...))). Собирать стектрейсы всегда и везде — смерть для производительности.

Впрочем Вы постоянно этим грешите, что поделать.

Очередное бездоказательное утверждение на эмоциях с вашей стороны :]

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

Это потому что у вас rank-n-полиморфизма, GADT и прочего нет, а оно бывает полезно, мягко скажем.

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

При этом в ML не нужно никаких IO монадов.

Как будто монады — это что-то плохое.

Хочешь писать императивно с изменяемыми переменными и циклами?

Теряешь возможность локально рассуждать о коде.

Я занимался аудитом кода на окамле, это ад. Код на хаскеле по сравнению с ним — это небо и земля.

При этом чем это принципиально лучше

count n = do
  i ← newIORef 0
  whileM_ ((< n) <$> readIORef i) $ do
    print =<< readIORef i
    modifyIORef' i (+ 1)

непонятно. Кроме того, что синтаксис чуть тяжелее, это да, но это как раз стимулирует сделать нормально для кратких примеров:

count n = mapM_ print [0 .. n - 1]

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

Тогда как вы пишете эту функцию?

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

не контр-тезис, а моё личное мнение - следствие четвертьвекового опыта программирования: математика не имеет почти никакого отношения к программированию.

Если честно, я довольно регулярно говорю, что для подавляющего большинства задач (и вакансий) в айти высшее образование и знание математики не нужны. Ну, потому что они правда не нужны, и можно пользоваться системой типов хаскеля без знания теории типов, и можно пользоваться этим вашим Array.reduce в жс без знания того, чем катаморфизмы отличаются от анаморфизмов, и почему reduce через map или filter выразить проблематично, а map или filter через reduce — без вопросов.

Но при этом каждый раз, когда я вижу такие заявления, как ваши, особенно в контексте воинственных постов «типы не нужны! ограничения и проверки для лохов! Настоящий Мужик программирует без защиты!», у меня возникают сомнения в собственной правоте. Может, математика на уровне хотя бы первого курса факультета прикладной математики (или хотя бы пара семестров матлога) правда нужна, чтобы мозги поставить и сформировать, даже если потом ты ей никогда не будешь [осознанно] пользоваться? Может, айтишечка с математическим цензом была бы более лучшим и приятным местом? Может, я просто не ценю то, что у меня есть?

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

Information

Rating
1,199-th
Registered
Activity