Перевод отрывка из интервью с создателем Node.js Раяном Далом (Ryan Dahl) в котором обсуждается модель программирования и язык Go.

— Расскажи нам, как проходила начальная разработка Node? Это ведь уже было достаточно давно, ты создал Node в 2009.

Райан: — Я думаю для себя лично, что нет лучшего момента в жизни, когда ты, как это говорится, «в потоке» и у тебя есть идея, в которую ты сильно веришь. И при этом есть время, чтобы сесть и на самом деле работать над ней. И я думаю, Node была именно такой идеей, которая ждала, чтобы её кто-то ухватил, и если бы не я, то это бы сделал кто-то другой. Но так случалось, что я был тогда достаточно свободен от работы и имел время, и мог работать нон-стоп несколько месяцев, которых как раз были нужны, чтобы выкатить начальную версию. Так что да, это был отличный период.

— Отлично, супер. Node построена на идее «полностью асинхронной» модели программирования. Удачна ли она была для Node?

Райан: — Да, это очень интересный вопрос. Уже вот несколько лет, как я не работаю над Node, ну, где-то, примерно с 2012 или 2013. И Node, конечно же, большой проект сегодня. Поэтому да, я думаю… когда она только вышла, я разъезжал и выступал на конференциях, пытаясь убедить людей, что они должны… что может быть мы совершенно неправильно делаем I/O подсистему и что, может быть, если бы всё начали делать в неблокирующем стиле, мы бы смогли решить огромное количество сложностей в программировании на Node. Ну, как, например, мы могли бы забыть про потоки полностью и использовать только абстракции процессов и сериализованную коммуникацию между ними. Но в одном процессе мы могли бы обрабатывать сразу много запросов, будучи полностью асинхронными. Я был ярым сторонником этой идеи в то время, но через пару лет, я понял, что это была не самая лучшая идея, решающая все проблемы в программировании. В частности, когда вышел язык Go… точнее, Go вышел достаточно давно, но когда я впервые начал о нём слышать, это где-то около 2012-го, у них, на самом деле, был очень приятный runtime, в которых были нормальные «зеленые потоки» и они реально строили абстракции вокруг них, и я начал думать про блокирующий ввод/вывод опять — ну, «блокирующий» в кавычках, — потому что это опять же все в «зеленых потоках»… между Go и операционной системой, так что по сути, я думаю, это всё же неблокирующий ввод-вывод.

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

— Да, мне тоже нравится модель программирования в Go. Использование горутин намного легче и fun. Мы, кстати, тоже Go используем на работе для распределённых систем.

Райан: — Да, я думаю, что для определённого класса приложений, как например, серверы — если вы пишете сервер, я не могу представить другой язык кроме Go. В общем, неблокирующая парадигма в Node работала очень неплохо для JavaScript, там где у вас нету потоков. И я думаю, что многие из тех проблем с callback hell, когда вам нужно прыгать в кучу разных функций чтобы закончить то, что вы делаете, в эти дни достаточно неплохо решены, с помощью async, например, который сейчас есть в JavaScript. То есть, как бы, новые версии Javascript делают жизнь немного проще. Учитывая всё это, я бы сказал, Node не лучшая система для массивных веб-серверов, я бы использовал Go для этого. И, если честно, это вобщем-то причина, почему я ушел из Node. Это было осознание: ох, ну реально, это далеко не лучшая система для серверного софта.

Да, я думаю, что Node на самом деле реально себя показала, как это ни странно, на клиентской стороне. Вроде скриптинга для построения веб-сайтов, или browserify, или bundles для клиентского Javascript кода. Ну или что можно делать всю эту серверную часть обработки клиентского Javastipt-кода. А потом, ну знаете, может быть небольшой сервер, чисто для девелопмента, там и тут, а потом может и настоящий сервер в продакшн, который будет получать реальный трафик. Node может быть полезной, или это может быть просто ваш выбор. Но если вы пишете распределённый DNS сервер, я бы не выбирал Node.

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


  1. WinPooh73
    04.09.2017 15:00

    Зачем в заголовке запятая после слова «серверов»?


    1. divan0 Автор
      04.09.2017 16:11
      +1

      Спасибо, это рефакторинг ) Оригинальная фраза была "Если вы пишете сервер, ...", но для краткости заголовка была заменена на "Для серверов", а запятая осталась.


  1. pawlo16
    04.09.2017 15:14
    -26

    Статья супер, спасибо. Буду тыкать носом в этот пост упоротых асинхронщиков и адептов js на сервере.


    1. gearbox
      04.09.2017 19:25
      +27

      я упоротый асинхронщик, куда именно в этой статье вы предлагаете меня ткнуть?


  1. impwx
    04.09.2017 15:28
    +10

    В транскрипции интервью нужно было избавиться от бесконечных «то есть», «в общем», «как бы» и прочих фраз-паразитов. С ними очень неприятно читать.


    1. radostnomne
      04.09.2017 16:10
      +5

      да и сам перевод как будто через гугл транслейт


      1. divan0 Автор
        04.09.2017 16:14
        +5

        Там текст достаточно сумбурный сам по себе, прямая речь.


    1. divan0 Автор
      04.09.2017 16:13
      +3

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


    1. ilnuribat
      04.09.2017 16:59
      +3

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


  1. justkost
    04.09.2017 16:10
    +11

    C async/await жизнь реально наладилась, а тут на тебе, переходи на go говорят!
    Ну фреймворк на ноде есть хороший уже, это я про koa2, еще бы cms уровня wordpress и вообще круто было бы)


    1. evocatus
      04.09.2017 20:59
      -6

      То, что вы купились на рекламу Node.JS — ваши проблемы. А советская модель «отучился в универе, больше учиться не надо, я теперь специалист» больше вообще нигде не работает, особенно в IT.


      1. justkost
        04.09.2017 21:09
        +5

        Ну у меня то выбор был простой, один язык и на клиенте и на сервере, плюс пакетный менеджер (npm), который теперь тоже и на клиенте и на сервере (это я про смерь bower-а)


      1. asmln
        05.09.2017 11:37
        +7

        Откуда вы взяли такую «советскую модель»? Даже Ленин призывал в своих публикациях непрерывно учиться.


        1. dmitry_dvm
          05.09.2017 12:12
          -6

          Учиться, учиться и еще раз учиться — это лучше, чем работать, работать и еще раз работать. Ленин.


          1. mrsweet
            05.09.2017 16:54
            +2

            Это Стейтем сказал, а не Ленин


            1. andreysmind
              05.09.2017 18:53
              +2

              Вы все неправы.

              Всегда говорит Аллах: «Надо учиться, учиться, надо учиться». Мы День знаний не отменили, потому что хотели побольше рассказывать про наш праздник религиозный, и чтобы они [школьники] пришли 1 сентября в школу, которую они ждали, и чтобы побольше был баракат, побольше было всего лучшего для наших детей.

              Рамзан Кадыров, глава Чечни


            1. dmitry_dvm
              07.09.2017 12:57

              Не знаю почему вы так думаете, мне лично Ленин это говорил.


  1. Stemy
    04.09.2017 16:10
    +7

    Да, я думаю, что Node на самом деле реально себя показала, как это ни странно, на клиентской стороне.


    Буквально год назад задумался о том, а к чему идёт вообще нода и правильно ли её использовать на сервере? Пришёл к выводу, что нода показывает себя сильнее всего на данный момент в фронте и перешёл на го. Как же я, оказывается, был прав.


    1. Nikelandjelo
      04.09.2017 23:33
      +11

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


  1. SuperPaintman
    04.09.2017 16:43
    +16

    Ну все, пойду переписывать все свои Node.js бэки на Go. А если серьезно, как-же достала это выдуманная проблема с языками и платформами (особенное с очень близкими по производительности). Т.е. выбор языка по бенчмаркам куда предпочтительнее, чем скорость разработки функционала / экосистема / синтаксис / высокоуровневость?


    сделай вот эту штуку А, подожди ответ, может быть упади с ошибкой. Потом сделай штуку Б, подожди ответ, проверь ошибку. И в Node это намного сложнее, потому что ты должен для этого прыгать в вызов другой функции.

    async function thingA() {
      // magic
    }
    
    async function thingB() {
      // magic
    }
    
    (async function main() {
      await thingA(); // И подождет ошибку, и сам упадет
    
      try {
        await thingB(); // Сделает штуку Б
      } catch (err) {
        // Проверит ошибку
      }
    })()
      .catch((err) => {
        console.error(err);
    
        process.exit(1);
      });

    Действительно, это гораздо сложнее и меннее читаемо чем постоянные if err != nil.


    «зеленые потоки»

    Event-loop не сравляется? Ок, fibjs, node-fibers, они должны быть чуть побыстрее. (нам ведь это реально нужно).


    Но если вы пишете распределённый DNS сервер, я бы не выбирал Node.

    А я бы выбрал C, нам ведь важны только бенчмарки, да?


    1. rraderio
      04.09.2017 16:48

      А может нам важна золатая середина? Не Node и не C, а Go?


      1. SuperPaintman
        04.09.2017 16:51
        +16

        Вы не правильно поняли мой посыл. Я не агитирую ни за Node, ни за Go. Я говорил, что есть вещи куда важнее, чем мериться бенчмарками и бесконечно переписывать с языка на язык (не забывайте, что скоро Rust станет меинстримом, и как заживем, как начнем рефакторить-переписывать :)).


        1. divan0 Автор
          04.09.2017 17:01
          +9

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


    1. SuperPaintman
      04.09.2017 16:48
      +10

      Если подытожить все сказанное выше, пишите на чем вам удобнее и привычнее. Не там много задач, где узким местом будет именно выбранные язык, а не сеть и взаимодействие с диском. А если уж вы и упретесь в один из таких случаев, то нет смысла переписывать всю систему на "+5% к производительности" языке, а лучше задуматься о низкоуровневой реализации этого "горлышка" или же нативном аддоне.


      1. divan0 Автор
        04.09.2017 17:10
        +2

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


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


        Knowledge debt сам себя не погасит с таким подходом. :)


        1. SirEdvin
          04.09.2017 17:20
          +6

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

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


          1. divan0 Автор
            04.09.2017 17:27
            -1

            И опять же, полностью согласен с вами в общем случае. Я тут как-то делал перевод статьи одного хаскелиста, который (как это принято) высмеивает Go, но, который, при этом признает, что он может попросить коллегу выучить Go за выходные, но не может это же сделать с Haskell или Purescript.
            https://habrahabr.ru/post/270707/


            Go это, всё таки, язык, в котором очень многие решения отталкиваются от социального аспекта программирования, коим "порог входа" и является. Он создавался именно с этим расчетом и авторы Go это много раз озвучивали.


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


            1. SirEdvin
              04.09.2017 17:35
              +6

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

              Не вижу проблем сделать это же, например, с python, ruby, java, nodejs и кучей других языков. В свое время, когда я только был студентом я осилил python за 15 минут. А вот с go у меня такое не получилось. Например, в силу того, что в отличии от python и golang странные для меня архитектурные решения в плане GOPATH (я тогда еще не знал, как нормально завести GOPATH везде и уж очень намучался с аналогичной проблеме в CUDA) и зависимостей, ну это такое.


              Ну и дополнительно:


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

              Эта штука работает только если проект на pure Golang, но в современной разработке очень популярна тенденция фрейворков и как только golang окончательно придет массы (например, с go 2.0), то оно все обернется кучей фрейворков и получится такая же проблема как и с другими языками.


              1. divan0 Автор
                04.09.2017 17:45
                -1

                Не вижу проблем сделать это же, например, с python, ruby, java, nodejs и кучей других языков.

                Почему? Вам кажется, что у всех языков одинаковая сложность и порог входа?
                Если да, то это странная точка зрения.


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

                Ага, некоторые люди прямо так и говорят — "я считаю, что Go ещё сырой, потому что под него мало фрейморков для микросервисов, в отличие от Scala, например".
                Но ничего не может быть дальше от истины, чем это утверждение. Это как говорить "я считаю Tesla еще сырая, потому что там нет отверстия для бензобака".


                Вы никогда не задумывались, почему создаются фреймворки? По-сути, фреймворк это "язык в языке", для решения специфической проблемы. Прелесть Go в том, что он зародился в 2007-м, в отличие от остальных мейнстримовых языков, которые уже по 20-30+ лет. Он родился тогда и в том месте, где такие вещи как микросервисы/RPC/JSON/криптография и т.д. были жизненной ежедневной необходимостью, поэтому практически всё это есть в стандартной библиотеке.


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


                1. SirEdvin
                  04.09.2017 18:33
                  +7

                  Почему? Вам кажется, что у всех языков одинаковая сложность и порог входа?
                  Если да, то это странная точка зрения.

                  Нет, у c++, scala, clojure, haskell значительно выше порог. Но это я к тому, что golang не пионер по низкому порогу входа.


                  Ага, некоторые люди прямо так и говорят — "я считаю, что Go ещё сырой, потому что под него мало фрейморков для микросервисов, в отличие от Scala, например".
                  Но ничего не может быть дальше от истины, чем это утверждение. Это как говорить "я считаю Tesla еще сырая, потому что там нет отверстия для бензобака".

                  Вы никогда не задумывались, почему создаются фреймворки? По-сути, фреймворк это "язык в языке", для решения специфической проблемы. Прелесть Go в том, что он зародился в 2007-м, в отличие от остальных мейнстримовых языков, которые уже по 20-30+ лет. Он родился тогда и в том месте, где такие вещи как микросервисы/RPC/JSON/криптография и т.д. были жизненной ежедневной необходимостью, поэтому практически всё это есть в стандартной библиотеке.

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

                  Верно. И где же в golang таки фичи, как:


                  1. ORM
                  2. Построение web приложений при помощи MVC
                  3. Traceback и умная работа с ошибками.

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


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


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


                  1. divan0 Автор
                    04.09.2017 18:48
                    -9

                    И где же в golang таки фичи, как:

                    ORM
                    Построение web приложений при помощи MVC
                    Traceback и умная работа с ошибками.



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


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

                    То есть для вас языки, в которых софт комьюнити состоит не из какой-то компании, по определению сырые? Ок, спасибо за (не очень) интересную дискуссию. Надеюсь ваша IDE, написанная компанией, уже запустилась, давайте работать.


                    1. SirEdvin
                      04.09.2017 19:04
                      +7

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

                      А вы предлагаете работать с базой при помощи чистых sql запросов? Это мало того, что не удобно, это еще делает ваш код базо-ориентированным и приводит к куче проблем с производительностью, безопасностью и прочему. Да, программисты не любят orm за странные вещи и то, что некоторые части таки приходится переписывать на чистый sql. Но писать все приложение на sql — это безумие.


                      То есть для вас языки, в которых софт комьюнити состоит не из какой-то компании, по определению сырые? Ок, спасибо за (не очень) интересную дискуссию. Надеюсь ваша IDE, написанная компанией, уже запустилась, давайте работать.

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


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


                      1. evocatus
                        04.09.2017 21:07
                        +3

                        В последнем проекте я пишу чистые SQL запросы. Неудобно? Пока не вникнешь в основы SQL, а они элементарные, особенно если полистать параллельно книгу Кристофера Дейта «SQL и реляционная теория».

                        это еще делает ваш код базо-ориентированным

                        А каким он ещё должен быть? Если вы используете базу, значит работаете с данными.
                        Да, программисты не любят orm за странные вещи и то, что некоторые части таки приходится переписывать на чистый sql. Но писать все приложение на sql — это безумие.

                        Понимаете, какая дилемма: ORM не лажает в простых случаях, в которых написать на чистом SQL тоже не так сложно (хоть и дольше), а в сложных случаях всё сложно: хоть на SQL, хоть на ORM. В общем, как всегда: магии не случилось и ты получаешь то, за что платишь (в данном случае знаниями и трудом).
                        Это мало того, что не удобно, это еще делает ваш код базо-ориентированным и приводит к куче проблем с производительностью, безопасностью и прочему.

                        Вот это уже полная ерунда. Все нормальные библиотеки для работы с базами предохраняют от SQL-injection на 100%, а грамотно написанный SQL ВСЕГДА быстрее работает, чем запросы от ORM.


                        1. SirEdvin
                          05.09.2017 00:10
                          +3

                          Понимаете, какая дилемма: ORM не лажает в простых случаях, в которых написать на чистом SQL тоже не так сложно (хоть и дольше), а в сложных случаях всё сложно: хоть на SQL, хоть на ORM. В общем, как всегда: магии не случилось и ты получаешь то, за что платишь (в данном случае знаниями и трудом).

                          Вы говорите так, как будто ORM работает как LINQ, вы упускаете вот такие штуки:


                          1. ORM следит за структурой базы данных
                          2. ORM предоставляет детальную информацию про структуру бд, которую можно использовать, например, для формирования ответов, запросов или еще чего-то (я, например, команды конфигурации так делают).
                          3. ORM позволяет добавлять к модели логику, которую в ином случае не совсем понятно где хранить.

                          И это все на чистом SQL делается только через страдания и шаблонный код. Ну или вы реализуете свою ORM.


                          Вот это уже полная ерунда. Все нормальные библиотеки для работы с базами предохраняют от SQL-injection на 100%, а грамотно написанный SQL ВСЕГДА быстрее работает, чем запросы от ORM.

                          1. Для сложных случаев грамотно написать SQL на проекте может, ну, 20% девов, так что лучше ORM.
                          2. Подскажите, как выбора по id для всех полей может быть написана быстрее, чем select * from table where id=<id>? Однострочники, которые генерирует ORM вряд ли будут сильно быстрее. Разве что у вас большая таблица и вы заранее знаете, какие поля будете использовать. А потом будете страдать и каждый раз дописывать поле в запрос.
                          3. psycopg2 нормальная? Для передачи параметров там нужно использовать специальную функцию, потому что простое cur.execute(query) не делает экранирования (что логично), а значит, если вы будете формировать запрос в обход предоставленного интерфейса, то у вас будет дыра.


                          1. Paskin
                            05.09.2017 08:58
                            +1

                            Универсального решения нет — где-то лучше ОРМ, где-то простые запросы или хранимые процедуры. По поводу же ОРМ — добавлю еще несколько проблем (решаемых, но все же):

                            1. В ОРМ как правило есть только одна модель сущности — из-за этого запросы возвращают все поля, даже если реально нужно одно-два
                            2. Бутстрап ОРМ в базе с большим числом обьектов может занять приличное время из-за чтения метаданных
                            3. Если вам нужны hint-ы, тем более разные у разных клиентов — это проблема
                            4. В ОРМ как правило есть кэш которым надо управлять если базой пользуется кто-то еще
                            5. Управление транзакциями в ОРМ может быть довольно нетривиальным


                            1. SirEdvin
                              05.09.2017 09:00

                              К сожалению, вы правы. В защиту orm могу сказать, что значительная часть ORM позволяет вам взять только отдельные поля, если это вам сильно нужно, ну и не везде есть кеш.


                              Но транзакции это да(


                          1. Archon
                            05.09.2017 12:11
                            +2

                            Для сложных случаев грамотно написать SQL на проекте может, ну, 20% девов, так что лучше ORM.

                            Одного решения для всех случаев нет.

                            В сложных случаях на больших проектах программист идёт к DBA и рыдает в жилетку, а тот его выслушивает, делает чашку кофе, и пишет километровое CREATE VIEW (или, в особо сложных случаях, хранимую процедуру, возвращающую датасет). После чего получившееся уже можно использовать как угодно, хоть напрямую, хоть через ORM.

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

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

                            P. S. psycopg2 абсолютно нормальная, просто не надо давать её использовать напрямую. Откройте к ней фиксированный интерфейс и принимайте только параметризованные запросы.


                          1. evocatus
                            05.09.2017 23:33

                            Для подавляющего большинства таблиц эти ваши ID (a.k.a. суррогатные первичные ключи) нафиг не нужны и жрут ресурсы, вынуждая делать множество JOIN по любому поводу. А всякие тупые ORM (типа Django ORM) просто вынуждают так делать.
                            Яркий повод — вспомогательные таблицы для отношений Many-To-Many, где ID не нужен, а первичным ключом может служить комбинация foreign key


                            1. SirEdvin
                              05.09.2017 23:36

                              Спорный вопрос, ведь есть же нормальные формы (если я вас правильно понял), зачем-то их придумали.


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


                            1. vintage
                              06.09.2017 08:40

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


                              1. evocatus
                                06.09.2017 20:06

                                Один пример с Many-To-Many я уже привёл.
                                Натуральные (иногда композитные ключи) могут заменить суррогагные почти всегда. Исключение — личные данные людей (даже комбинация фамилия, имя, отчество, дата_рождения не может по-хорошему считаться уникальной) или когда натуральный ключ получается совсем уж развесистым, что скажется на производительности.

                                Например, есть таблица authors и таблицы books.
                                Если таблица authors однозначно сопоставима с таблицей persons (где хранятся имена/фамилии людей и уже есть суррогатный ID по причинам, описанным выше), то первичным ключом для authors может быть foreign key на persons.
                                Для таблицы books можно взять в качестве первичного ключа ISBN (он сюда так и просится) или комбинация дата_публикации, название или что-то ещё.

                                Тогда таблица books_by_authors, суть которой заключается в двух foreign key на authors и на books может спокойно иметь первичный ключ, являющийся комбинацией этих foreign key.

                                В итоге суррогатные ID будут только у самых базовых сущностей (и то не у всех), а все остальные будут иметь натуральные (иногда композитные) ключи


                                1. vintage
                                  06.09.2017 20:27

                                  "Для изданий, выходящих малым тиражом (в издательской практике 2003 года — до 1 000 экземпляров), либо для «личного» использования присваивать номер ISBN необязательно."


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


                                  "Международная стандартная нумерация книг не распространяется на" и там длинный список.


                                  https://ru.wikipedia.org/wiki/Международный_стандартный_книжный_номер


                                  Давайте ещё пример.


                                  1. evocatus
                                    06.09.2017 23:34

                                    Не проблема. Значит будет другой ключ.


                                    1. vintage
                                      07.09.2017 07:07

                                      Ничего, кроме суррогатного ключа, не гарантирует вам полноту, стабильность, компактность и уникальность.


                          1. Jef239
                            06.09.2017 04:47
                            +1

                            Для сложных случаев грамотно написать SQL на проекте может, ну, 20% девов, так что лучше ORM.

                            я бы сказал так: 20% разработчиков понимают, какой ужас делает ORM и могут написать в разы быстрее. Остальные — пишут примерно на уровне ORM.

                            Хотите скорости — пишите на SQL, хотите гибкости в ущерб скорости — используйте ORM. Ну и отсылаю к замечательной книжке бывшего коллег "Дефрагментация мозга".


                            1. vintage
                              06.09.2017 08:41

                              А можно получить и скорость и гибкость, если не цепляться за РСУБД, а взять графовую СУБД.


                            1. VolCh
                              07.09.2017 22:06

                              Вы как-то противопоставляете ORM и вручную написанный SQL. ORM ничего не говорит о том как получается SQL при работе с объектами. Как-то. Хотите пишите вручную, хотите — генерируйте каким-нибудь квери-билдером на основе метаданных из ОРМ.


                        1. eneko
                          05.09.2017 16:53

                          это еще делает ваш код базо-ориентированным

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



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


                          грамотно написанный SQL ВСЕГДА быстрее работает

                          … только если его пишет специалист с опытом работы с конкретной базой данных, разбирается в планах и индексах и вообще полу-DBA. Запрос, работающий быстро в Firebird, тормозит как черепаха в MSSQL, например. И наоборот.


                          Все нормальные библиотеки для работы с базами предохраняют от SQL-injection на 100%

                          Только до тех пор, пока программист не пытается программно сгенерировать сам SQL.


                          1. rraderio
                            05.09.2017 16:54
                            +1

                            Захотел сменить MySQL на Postgres? Переписывай большинство запросов.

                            И как часто вы меняли базу?


                            1. VolCh
                              05.09.2017 21:14

                              За последние 10 лет трижды менял и раз 5 отговаривал тех, кто слушая моё «нытьё» про мускуль и мскуль, говорили «так давай поменяем — пары недель хватит без отрыва на текущие задачи?». В двух случаях была ОРМ для, как минимум, бизнес-логики. После третьего стал отговаривать, если её не было.


                            1. eneko
                              06.09.2017 22:44

                              Interbase->Firebird, MySQL->Postgres, Firebird -> MSSQL… Слишком часто. Веб-проекты вообще часто вынуждены были подстраиваться под то, что даёт провайдер, или под объём памяти на инстансе.


                        1. VolCh
                          05.09.2017 21:05
                          +1

                          Если я использую базу данных в качестве хранилища данных, это ещё не значит, что моё приложение ориентируется на неё. Стараюсь писать так, чтобы базу данных можно было «моментально» заменить на файловое или веб-хранилище, на хранилище в памяти, на что угодно, что можно свести к коллекции объектов или подобных им структур данных, тесно связанных с поведением системы.


                      1. divan0 Автор
                        04.09.2017 22:40
                        -2

                        А вы предлагаете работать с базой при помощи чистых sql запросов?

                        Именно. Попробуйте, это не так сложно, как кажется, но в разы более надежно, особенно когда приходится отлаживать проблемы. ORM очень спорная штука — далеко не всегда базу можно красиво "замаппить" на объектную модель языка. SQL не так страшен, как вам может казаться.


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

                        И что? У вас тоже нет гарантии, что компании, которые вы так тут хвалите (мы все знаем, на какую компанию вы намекаете, но опустим этот момент), не обанкротятся и не забросят библиотеки. Абсолютных гарантий нет, но open-source коммьюнити оказывается часто гораздо более живучи и адекватны многих "компаний". Если следовать вашей логике, то Linux как явление вообще не могло существовать — нет же гарантий, что разработчики-энтузиасты не забросят его. А он есть.


                        но для компании использовать такие инструменты довольно небезопасно. Я не прав?

                        Вы, скорее, пытаетесь подтвердить свой confirmation bias, а не разобраться и судить о проблеме объективно.


                        1. SirEdvin
                          05.09.2017 00:04
                          -1

                          Именно. Попробуйте, это не так сложно, как кажется, но в разы более надежно, особенно когда приходится отлаживать проблемы. ORM очень спорная штука — далеко не всегда базу можно красиво "замаппить" на объектную модель языка. SQL не так страшен, как вам может казаться.

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


                          И что? У вас тоже нет гарантии, что компании, которые вы так тут хвалите (мы все знаем, на какую компанию вы намекаете, но опустим этот момент), не обанкротятся и не забросят библиотеки. Абсолютных гарантий нет, но open-source коммьюнити оказывается часто гораздо более живучи и адекватны многих "компаний". Если следовать вашей логике, то Linux как явление вообще не могло существовать — нет же гарантий, что разработчики-энтузиасты не забросят его. А он есть.

                          Компанию дают хоть какую-то гарантию. Например, spring и django курируются компаниями. Linux для бизнеса и не существовало, пока не появились такие штуки как Linux Fundation, Canonical, RedHat. А гарантом того, что они не обанкротятся служат другие компании, которые их спонсируют и используют их продукты.


                          Open-source часто оказывается, а часто и не оказывается. И играть в такую лотерею вроде бизнесу не хочется?


                          Вы, скорее, пытаетесь подтвердить свой confirmation bias, а не разобраться и судить о проблеме объективно.

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


                          Вот есть шикарная библиотека bumpversion, которая отлично работает и решает некоторые проблемы версионности и которая… не поддерживается с 2015 года. И много людей ее использует, даже делают форки, но в силу того, что pypi пакет никто не может отозвать ее развитие остановилось навсегда. И таких примеров можно найти достаточно.


                          1. divan0 Автор
                            05.09.2017 00:47
                            -6

                            И таких примеров можно найти достаточно.

                            Вы просто демонстрируете мой поинт. Вместо того, чтобы разобраться в теме, вы типичным cherry-picking-гом (это форма confirmation bias-а) находите пример, подтверждающий вашу точку зрения, и выдаете его за "доказательство". Если бы вы хотели разобраться объективно в теме — вы бы поискали библиотеки, которые не были заброшены, посчитали бы статистику и сделали выводы.
                            Скучно.


                            1. SirEdvin
                              05.09.2017 08:20
                              +3

                              Когда у вас нет хватает аргументов, вы начинаете применять не очень честные приемы риторики?
                              Чем мой confirmation bias хуже вашего? У вас так же нет статистики, данных или еще чего-то.


                              Причем у меня это даже не confirmation bias, так как мой поинт в том, что полезные, крутые и удобные open-source проекты, которые не пользуются поддержкой спонсоров могут быть запрошены (а есть ли пример того же, но с поддержкой спонсоров, который пропал не по схеме "денег становилось все меньше и меньше?). А это дополнительные риски для бизнеса, так как тогда нужно будет выделять людей, которые будут поддерживать это решение и исправлять в нем недочеты.


                              1. divan0 Автор
                                05.09.2017 09:15
                                -5

                                Чем мой confirmation bias хуже вашего?

                                Тем, что вы его подкармливаете и лелеете, а я со своими борюсь активно.


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

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


                                1. SirEdvin
                                  05.09.2017 10:41
                                  +1

                                  Ну окей, давайте на конкретном примере.


                                  Вот вы CTO крупной компании и начинаете новый проект. Это будет еще один web проект, с кучей интересных штук. Проект планируется на 5 лет.


                                  Вы можете взять известный вам уже язык (например, python) и знакомый стек технологий django + celery, который точно знаете, что еще довольно долго будут на плаву хотя бы по тому, что их используют и спонсирую крупные компании.


                                  С другой стороны, у вас есть golang, в случае которого, если вам нужен ORM, то у вас по факту есть только xorm, так как другие проекты ведут в целом по одному человеку. Если вам нужна очередь отложенных задач, то у вас в целом нет проектов, которые бы поддерживали хотя бы группы людей, а не один человек.


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


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


                                  1. divan0 Автор
                                    05.09.2017 11:04
                                    -2

                                    Если вы как CTO свели выбор платформы к вашим субъективным оценкам гарантий риска смертности авторов ORM библиотеки (которую вы сами нагуглили и решили, что она единственная), то такой из вас себе CTO. :)


                                    1. SirEdvin
                                      05.09.2017 11:18
                                      +2

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

                                      1. Я указал, что этот вопрос не единственный.
                                      2. Я нашел где-то штук 7. Можно глянуть тут. Одна перешла к фреймворк (которых, как вы считали, go не нужно), еще одна вроде как не orm вовсе. А остальные поддерживаются одним человеком, я написал, что сделал выбора исходя из этого.
                                      3. Это не субъективные оценки. Это называется bus factor. И очень грустно, когда он внезапно не зависит от компании вовсе.
                                      4. Ну и самое главное. Можно было еще заметить, что я упомянул еще task queue, положение которых в golang еще хуже. Сказали бы хотя бы, что я свел выбор платформы к двум факторам, а это получается какой-то confirmation bias.


                                      1. divan0 Автор
                                        05.09.2017 11:19
                                        -5

                                        Вы вправду не видите логической ошибки в вашей логике? Или специально накручиваете количество комментариев? :)


                                        1. SirEdvin
                                          05.09.2017 11:21
                                          +3

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


                                          В чем тут ошибка?


                                          1. divan0 Автор
                                            05.09.2017 11:29
                                            -5

                                            • язык это не ORM
                                            • гарантий абсолютных нет нигде
                                            • нужные экосистеме библиотеки, которые забрасываются — это исключение
                                            • это одинаково справедливо для любых языков
                                            • и даже эти проблемы решаемы

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


                                            Это же азбука логики.


                                            1. SirEdvin
                                              05.09.2017 11:39
                                              +2

                                              гарантий абсолютных нет нигде

                                              Да? Вот я знаю, что Linux не загнется, потому что есть linux foundation, я знаю, что django тоже останется на плаву, потому что есть Django Software Foundation, я знаю, что с golang будет все в порядке, потому что есть Google, который его использует.


                                              А кто работает с task queue на golang? Как много компаний используют orm? Большинство проектов вообще не используют sql, а всякие kv базы, как kubernetes, docker и так далее.


                                              язык это не ORM

                                              Язык это еще и инфраструктура, выработанные решения и фреймворки.


                                              1. divan0 Автор
                                                05.09.2017 11:43
                                                -5

                                                Вот я знаю, что Linux не загнется, потому что есть linux foundation

                                                Представляю как бы вы разглагольствовали до 2000, пока не было Linux Foundation :)


                                                А кто работает с task queue на golang?

                                                Все. А в ваших привычных языках для этого разве нужны отдельные библиотеки? :)


                                                Большинство проектов вообще не используют sql, а всякие kv базы

                                                Right tool for the right job. Или вы все пишете через ORM, там где даже не нужна реляционная модель данных?


                                                Язык это еще и инфраструктура, выработанные решения и фреймворки.

                                                Ага. Проблема-то в чём? Угадайте сколько за 4 года использования Go тысячами компаний в мире библиотек перестало поддерживаться и похоронило проект?


                                                1. SirEdvin
                                                  05.09.2017 11:50
                                                  +1

                                                  Все. А в ваших привычных языках для этого разве нужны отдельные библиотеки? :)

                                                  А в golang отложенная очередь идет из коробки? зачем тогда вот этот проект? Ну и несколько таких же.


                                                  Right tool for the right job. Или вы все пишете через ORM, там где даже не нужна реляционная модель данных?

                                                  Вы сместили акцент моего комментария в другую сторону. Суть была в том, что самые известные проекты на go не используют orm, так что он вроде как и не нужен для инфрастуктуры то особо.


                                                  Ага. Проблема-то в чём? Угадайте сколько за 4 года использования Go тысячами компаний в мире библиотек перестало поддерживаться и похоронило проект?

                                                  Думаю, тысячи. И это только не известных. Загляните, например, вот сюда и посмотрите на количество проектов, которые уже не поддерживаются год или два. А это 9 из 17 проектов, если я правильно посчитал. Проекты, которые не получают спонсоров довольно часто пропадают, когда у автора пропадает желание им заниматься. И к сожалению, это естественно.


                                                  Представляю как бы вы разглагольствовали до 2000, пока не было Linux Foundation :)

                                                  А до Linux Foundation был redhat. Думаю, два года люди как-то пожили без linux)


                                                  1. divan0 Автор
                                                    05.09.2017 13:22
                                                    -1

                                                    зачем тогда вот этот проект?

                                                    Это распределенный task queue c кешем и стораджем.


                                                    Думаю, тысячи.
                                                    посмотрите на количество проектов, которые уже не поддерживаются год или два

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


                                                    1. SirEdvin
                                                      05.09.2017 13:56
                                                      +3

                                                      что почти нереально в других языках

                                                      Простите, что? Вы когда-то использовали какие-то языки помимо go или только страшные статейки читали?


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

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


                                                      1. vintage
                                                        05.09.2017 14:00
                                                        +1

                                                        Или каждый проект написанный на Golang отливается в граните и является идеальным с самого начала?

                                                        Конечно, это ж фича языка: "никаких новых фич после версии 1.0" :-D


                                                        1. SirEdvin
                                                          05.09.2017 14:04

                                                          У них там gc менялся вроде)


                                                          1. vintage
                                                            05.09.2017 14:10
                                                            +1

                                                            Так это фича рантайма — её апгрейдить можно ;-)


                                              1. evocatus
                                                05.09.2017 23:54

                                                Никакие фаундейшены не спасут, если что-то случится с Линусом Торвальдсом или Грегом Кроа-Хартманном. Они лично значат так много, что это будет сильным ударом по самому процессу разработки, не говоря уже о стратегическом развитии и пр.


                                                1. SirEdvin
                                                  06.09.2017 06:58

                                                  Уверены? Судя вот по этой статье, весьма спасут. Да, это будет сложное время для Linux, но я думаю, они вполне справятся.


                                          1. CuredPlumbum
                                            05.09.2017 13:41
                                            +1

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

                                            Гарантий нет, даже, если вы купите какой-либо фреймворк/библиотеку/продукт. У вендоров даже есть опция: при покупке какого-либо продукта предусматривается доступ к исходным кодам, если компания-продавец почила в бозе.

                                            А для Go идеология Google — развивать и затягивать из открытых исходников к себе. А не развивать у себя, и открывать уже вовне.


                                            1. SirEdvin
                                              05.09.2017 13:57

                                              А для Go идеология Google — развивать и затягивать из открытых исходников к себе. А не развивать у себя, и открывать уже вовне.

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


                                              1. divan0 Автор
                                                05.09.2017 14:11
                                                -1

                                                У них там gc менялся вроде)

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


                                                1. SirEdvin
                                                  05.09.2017 14:13

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


                                                  Если этой простой проект, который делает одну функцию, то его код может не меняется годами. Но если это сложный проект, например, orm, то тут все становится хуже.


                                                  1. divan0 Автор
                                                    05.09.2017 14:16
                                                    -1

                                                    Вы когда нибудь работаете, или всё ещё ждёте, пока загрузится IDE?


                                                    1. SirEdvin
                                                      05.09.2017 14:36

                                                      Я использую Sublime, он быстро грузится.


                                                1. vintage
                                                  05.09.2017 14:15

                                                  Он может начать дико тормозить или падать с нехваткой памяти.


                                              1. CuredPlumbum
                                                05.09.2017 14:21
                                                +1

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


                                                Что конкретно отвратительно? Вести разработку библиотек в открытом виде?

                                                Если нет готового, сделайте форк этой утилиты — допишите API. Мне понадобился gowsdl, я просто поправил под себя.


                                                1. SirEdvin
                                                  05.09.2017 14:37

                                                  Хранить зависимости в одном репозитории с кодом. Это приводит к тому, что их никто не обновляет и оно там и застряет навсегда :(


                        1. VolCh
                          05.09.2017 21:25

                          Дело не в том, как работать с базой, дело именно в маппинге её на объектную модель. Вы, кажется, один из немногих, кто понимает, что ОРМ — это не инструмент, генерирующий под капотом скуль на основе аннотаций или конфигов рядом с основным кодом, а то и с помощью квери-билдера, малоотличимого от скуля. Мало кто понимает, что ОРМ может быть не универсальным, может быть написан на «чистом скуле», максимально оптимизированном, что если есть полноценные объекты и реляционная БД как средство обеспечения их персистентности, то ОРМ уже есть, даже если каждый запрос захардкожен, а поля объектов заполняются по числовому индексу.


                1. PashaNedved
                  05.09.2017 11:13

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

                  Фреймворк — это как IDE, он объединяет несколько/множество инструментов для решения разнообразных задач. И совсем не обязательно, чтобы эти инструменты были необходимой частью фреймворка, напротив, если он не содержит этих инструментов, а служит лишь интерфейсом, то это вообще замечательно.
                  Тоесть фреймворки в других языках существуют, потому что самого языка и его стандарного набора не хватает. В Go хватает.
                  Фреймворки существуют, потому что делают процесс разработки быстрее и удобнее (Осторожно, вызывает привыкание). Если вам хватает стандартного набора Go, то зачем использовать «левые» пакеты?


    1. divan0 Автор
      04.09.2017 17:17
      -2

      Кстати, по вашему примеру кода — чисто субьективные впечатления после Go:


      • async/await просто лишний когнитивный балласт (в сравнении с Go, опять же)
      • без комментария не понятно, что произойдет при ошибке в thingA(), пока не проскроллишь глазами в самый низ (и это на микроскопическом примере уже не очень приятно)
      • try { } catch (err) { } конструкция гораздо более громоздка, голословна, и при этом менее ясна, чем if err := thingB(); err != nil {... }. 5 строк против 3, при нулевых бенефитах в данном случае, и еще и спрятанной магией передачи ошибки.
      • снова же, приходится бегать глазами от начала main до конца, чтобы понять, точно ли не упустил ничего из этого flow-а программы, раскиданным в нескольких местах.

      Ну это я так, набросил. Когнитивная нагрузка у JS таки выше.


      1. SirEdvin
        04.09.2017 17:25
        +5

        try { } catch (err) { } конструкция гораздо более громоздка, голословна, и при этом менее ясна, чем if err := thingB(); err != nil {… }. 5 строк против 3, при нулевых бенефитах в данном случае, и еще и спрятанной магией передачи ошибки.

        Справедливости ради есть вот такая штука, которая значительно удобнее err !=nil. Более того, вы упускаете тот факт, что err!=nil вам нужно будет пихать после каждого вызова, который вам нужно обрабатывать, а в try блок можно завернуть большое количество строк кода и отловить ошибку в самом конце.


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

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


        1. divan0 Автор
          04.09.2017 17:39
          -2

          Более того, вы упускаете тот факт, что err!=nil вам нужно будет пихать после каждого вызова, который вам нужно обрабатывать, а в try блок можно завернуть большое количество строк кода и отловить ошибку в самом конце.

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


          А вот в вашем примере это возможность "завернуть большое количество строк кода" абсолютно ни к чему. Зато приводит к следующему:


          • уменьшает локальность кода — вам нужно прыгать глазами вниз функции, чтобы вообще узнать, как обрабатывается ошибка и обрабатывается вообще, при этом держать в памяти вызов, пока вы прыгаете (когнитивная нагрузка)
          • прячет от вас ясность того, что происходит и какой оверхед от передачи ошибки (она ж таки где-то там передается сама при throw, но у вас нет шанса это узнать, кроме как изучить внутренности устройства exceptions в JS)
          • прячет от вас понимание того, вообще возвращает функция ошибку или нет
          • создает лишнюю нагрузку на производительность и расход памяти (вам всего-то надо передать одну переменную, а рантайм там целые стектрейсы в фоне гоняет, выделяя память, и никакой видимости этого нет)
          • ну и менее очевидное, но очень важное (и мое любимое), заставляет вас относится к ошибкам, как к "не сильно важному коду, который нужно засунуть подальше".

          И вот в этом двухстрочном примере у вас же и выбора нет. Вы действительно должны использовать этот 5 строчный громоздкий блок с кучей проблем, потому что "удобный вам язык" предоставляет только такую модель. А в Go при желании можно сделать что угодно — "ошибки" это просто интерфейсные переменные. Можно даже try..catch… реализовать для тех кейсов где это нужно, но оно правда лишнее.


          1. SirEdvin
            04.09.2017 18:25
            +4

            Такие ситуации, действительно, имеют быть, но они чаще исключение, чем норма, да и для них в Go можно сделать красивые решения.

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


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

            Зато увеличивает бессмысленность кода. Это отлично, когда каждая ошибка обрабатывается умно и отдельно, но мне кажется, что 99% ошибок в golang просто выкидывают в лог или прокидывают дальше.


            прячет от вас ясность того, что происходит и какой оверхед от передачи ошибки (она ж таки где-то там передается сама при throw, но у вас нет шанса это узнать, кроме как изучить внутренности устройства exceptions в JS)

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


            прячет от вас понимание того, вообще возвращает функция ошибку или нет

            Спасает документация или такие штуки как в Java. Более того, документация вида raises в python мне нравится больше, так как она дает понимание какого рода ошибка вернется, чего не дает простой err в golang. Ну и да. Как вообще вот эта функция работает, если там в конце возвращает одна переменная, а не две? иногда ошибка, иногда нет?


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

            Ну, а так вы пробрасываете ошибку и теряете весь traceback. На мой взгляд информация про ошибку значительно важнее мифических 4-8МБ.


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

            Эм… а вы уверены? У вас так же 99% ошибок выкидывается. Как видите, это не помогло.


            И вот в этом двухстрочном примере у вас же и выбора нет. Вы действительно должны использовать этот 5 строчный громоздкий блок с кучей проблем, потому что "удобный вам язык" предоставляет только такую модель. А в Go при желании можно сделать что угодно — "ошибки" это просто интерфейсные переменные. Можно даже try..catch… реализовать для тех кейсов где это нужно, но оно правда лишнее.

            В других языках так можно делать тоже. В python их можно просто игнорировать, в java можно сделать метод для экранирования. А golang заставляет вас эмулировать traceback без самого traceback своими силами. Возможно идеология за этим стояла другая, но получилось у людей так. И какой тогда в этом смысл?


            1. divan0 Автор
              04.09.2017 18:41
              -3

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

              Там вполне ок код — три возврата это не проблема. Мне бы было интересно, кстати, как бы вы переписали второй пример на эксепшенах :)
              Я как-то слышал аргумент про возвращаемые значения от людей, которые не сильно поняли разницу между возвращаемыми ошибками в Go и С: "Тот, кто работал с возвращаемыми кодами ошибок в ядре Linux, больше никогда такого не захочет". А потом попытался представить как бы ядро Linux выглядело, если было бы написано с помощью эксепшенов. Думаю, не было бы у нас Linux.


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

              Именно об этом и речь.


              но мне кажется, что 99% ошибок в golang просто выкидывают в лог или прокидывают дальше.

              И супер. А что еще делать с ошибками? Это самые популярные варианты, разумеется. Но это не просто "прокинуть дальше" — это логичный и понятный flow программы для программиста, который читает код. Не забыайте, что язык программирования это не столько язык для общения человека с компьютером, сколько человека с человеком.


              А так вам нужно изучать оверхед блока if

              И какой-же там оверхед? :) Одна CMP инструкция?


              Спасает документация

              Безусловно, это не была нерешаемая проблема. Можно написать специальные IDE для языка, которые будут это делать, можно даже автору кода позвонить и спросить, что функция должна вернуть. Только это высокая стоимость для такой обыденной операции, которую делаю миллионы программистов много раз за день. Фред Брукс это называет "добавленной сложностью" — которую мы сами приносим с новыми языками/технологиями. Её нужно уменьшать как только можно.


              Ну, а так вы пробрасываете ошибку и теряете весь traceback.

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


              У вас так же 99% ошибок выкидывается.

              Вы всё ещё считаете, что "проброс ошибки наверх" это лишняя операция, от которой нужно избавиться? Про локальность и понятность кода я уже выше писал, не хочу повторяться.


              А golang заставляет вас эмулировать traceback без самого traceback своими силами.

              Опять же, если нужен стектрейс, используют либо panic() (fail fast), либо debug.PrintStack(). Можно и просто в переменную error стек сохранять, есть удобные либы для этого. В Go есть выбор, гибкость и очень разумные дефолтные значения.


              1. SirEdvin
                04.09.2017 18:56
                +2

                Там вполне ок код — три возврата это не проблема. Мне бы было интересно, кстати, как бы вы переписали второй пример на эксепшенах :)

                Мне довольно сложно понять, что именно там происходит, но, например, на python это будет просто цикл через os.walk и raise из цикла.


                Я как-то слышал аргумент про возвращаемые значения от людей, которые не сильно поняли разницу между возвращаемыми ошибками в Go и С: "Тот, кто работал с возвращаемыми кодами ошибок в ядре Linux, больше никогда такого не захочет". А потом попытался представить как бы ядро Linux выглядело, если было бы написано с помощью эксепшенов. Думаю, не было бы у нас Linux.

                Я думаю, надо писать статью "Ваше веб-приложение не ядро Linux".


                И супер. А что еще делать с ошибками? Это самые популярные варианты, разумеется. Но это не просто "прокинуть дальше" — это логичный и понятный flow программы для программиста, который читает код. Не забыайте, что язык программирования это не столько язык для общения человека с компьютером, сколько человека с человеком.

                То есть? Это два варианта "обработать тут" или "прокинуть дальше". Оно так работает везде, но только golang заставляет вас выбирать каждый раз, а не дает возможность выбрать поведение по умолчанию.


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

                1. А в каких еще случаях должны выводится ошибки, если не в тех, когда разработчику нужен traceback?
                2. Вложенность функций все равно остается. И не совсем представляю, как можно оставить маленькие читаемые функции, маленький уровень их вложенности и при этом писать сложные приложения.
                3. Java тоже используется в таких случаях, и ей почему-то все "кчему".

                Вы всё ещё считаете, что "проброс ошибки наверх" это лишняя операция, от которой нужно избавиться? Про локальность и понятность кода я уже выше писал, не хочу повторяться.

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


                Опять же, если нужен стектрейс, используют либо panic() (fail fast), либо debug.PrintStack(). Можно и просто в переменную error стек сохранять, есть удобные либы для этого. В Go есть выбор, гибкость и очень разумные дефолтные значения.

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


                очень разумные дефолтные значения

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


                1. divan0 Автор
                  04.09.2017 19:00
                  -5

                  А в каких еще случаях должны выводится ошибки, если не в тех, когда разработчику нужен traceback?
                  Например "порт занят" или "db/users.go:45: ошибка в SQL: такая-то такая то".

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


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

                  Именно. Уменьшая когнитивную нагрузку для того, кто будет читать это код потом.


                  Я думаю, надо писать статью "Ваше веб-приложение не ядро Linux".

                  Go это не веб-фреймворк.


                  1. SirEdvin
                    04.09.2017 19:08
                    +4

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

                    Мне кажется, вариантов где они нужны, все-таки больше. Хотя тут нужна какая-то статистика.


                    Именно. Уменьшая когнитивную нагрузку для того, кто будет читать это код потом.

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


                    Go это не веб-фреймворк.

                    А для чего он тогда нужен? Драйвера все равно будут писать на C, десктопные штуки на нем писать точно не будут, остаются только системные утилиты, которые пишутся на том, что получится и web-сервисы. Ну и embedded в котором я не разбираюсь.


                    embedded это отлично, но потеснить там C так же будет сложно


                    1. Nakosika
                      04.09.2017 22:47

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


                      1. SirEdvin
                        05.09.2017 00:13

                        Я, кстати, добрался до google, и, например, для python такая возможность есть.


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


                        Например, у вас где-то отваливается коннект, вы знаете, что в конкретном месте, но вместо traceback у вас в логах просто куча сообщений вида "socket connection reset:49". Такие ситуации обычно куда хуже, чем небольшое излишество от traceback.


                        1. divan0 Автор
                          05.09.2017 00:51
                          -3

                          У меня тут непопулярная точка зрения, но у меня во многих проектах вместо трейсбеков стоят просто в начале строки в логгере путь к файлу и номер линии:
                          - [timestamp] path/file.go:42: Failed to connect to server: connection reset
                          и этого не просто с головой хватает, но еще и красиво, удобно и очень ускоряет процесс использования логов в дебаг-сессиях.


                          Трейсбек тут понадобится только тогда, когда структура программы станет запутанной и страшной, и ошибка будет исходит из неверных параметров, и родительских функций может быть 20 разных вариантов и тд. Тогда да. Но пока программы не гигантские и не спагетти — file:num хватает с головой.


                          1. SirEdvin
                            05.09.2017 08:23

                            Как я понял, у вас кроме микросервисов и embedded проектов, получается, ничего и нет?


                            1. divan0 Автор
                              05.09.2017 09:17
                              -3

                              Как всегда, неправильно поняли.


                    1. JekaMas
                      05.09.2017 06:49

                      Пишем мобильные приложения на go + демонов-обработчиков данных.


                      1. SirEdvin
                        05.09.2017 08:22
                        -1

                        Хм, круто! Подскажите, как там с дизайном? Я просто как-то раз попробовал похожую штуку на python, столкнулся с прискорбным фактом того, что не хватает кучи необходимых компонентов из material design и загрустил.


            1. Falstaff
              04.09.2017 18:47
              +1

              Я не автор статьи (и не переводчик), но всё-таки хочу заметить, что ваши рассуждения не универсальны. Оверхед блока if виден невооружённым взгядом — вы в общем-то можете заранее сказать, какого вида машинный код в этом месте будет сгенерирован и как будут возвращаться результаты. В случае с исключением всё уже сложнее, вам придётся его именно что изучать. (Да, по поводу того, какого рода ошибка — в Go вроде бы можно именовать возвращаемые значения.) По памяти оверхед тоже важен — в embedded, например (реализация исключений в gcc использует чудовищный размер стека при его раскрутке, и этот размер вам приходится давать каждой задаче, если у вас RTOS).


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


              1. SirEdvin
                04.09.2017 18:59
                +2

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

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


                1. Falstaff
                  04.09.2017 19:09

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


                  Я вот апокрифичный пример из C++ Annotations вставлю:


                  void fun() {
                    X x;
                    cout << x;
                    X *xp = new X{ x };
                    cout << (x + *xp);
                    delete xp;
                  }

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


                  Можно долго не думать

                  В тринадцати. Вот задумайтесь — тринадцать нелокальных невидимых goto в функции из пяти строк. Если вы выделили в функции какие то ресурсы и/или хотите поддерживать какие-то exception guarantees, вы должны их видеть. Везде. Исключения — отличная штука, но начинающим они бьют по мозгам; чтобы использовать их безопасно, нужен определённый стиль мышления, сам по себе он не вырабатывается, нужны практика и время.


                  1. SirEdvin
                    05.09.2017 00:18
                    +1

                    А теперь представьте, как это выглядело бы с другим подходом. 5 строчек существенного кода и 39(!) строчек вида if err!=nil {}.


                    Мне кажется, оба варианта плохи, тут скорее код нужно исправлять.


                    1. divan0 Автор
                      05.09.2017 00:37
                      -2

                      и 39(!) строчек вида if err!=nil {}.
                      Мне кажется, вы не поняли, почему в примере выше взялось 13 мест, и просто умножили 13 на 3, чтобы подпитать свой confirmation bias и самого же себя убедить в том, что вы правы. :)


                      1. SirEdvin
                        05.09.2017 08:24

                        Да, вы правы.
                        Давайте умножим 5 на 3 и получилим — 15 строчек. 75% всего кода — это шаблонный код, который не несет смысловой нагрузки.


                        Стала ли ситуация лучше?


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


                        1. divan0 Автор
                          05.09.2017 09:29
                          -6

                          который не несет смысловой нагрузки.

                          День, когда вы начнете видеть смысловую нагрузку в обработке ошибок будет самым важным днём вашей карьеры.


                          1. SirEdvin
                            05.09.2017 10:53

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


                            if err != nil {
                                return nil, err
                            }

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


                            Более того, как отметили ниже, вопрос перформанса тоже может быть спорный, потому что в какой-то момент количество if проверок станет настолько велико, что по замедлению производительности побьет плату, которую мы несем за возможность raise в python, хотя вряд ли ее можно оценить отдельно от всего runtime в python.


                            1. divan0 Автор
                              05.09.2017 11:01
                              -4

                              Нет никакого реального профита, исключая вопросы перформанса, вставлять

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


                              1. SirEdvin
                                05.09.2017 11:08
                                +3

                                Но ведь это не так. Когда я пишу raise Exception я всегда понимаю, что эта ошибка или будет обработана выше (а если таких мест много, то нужно ставить вопрос о рефакторинге) или обработается фрейморков и выдаст сообщение про ошибку, или уронит программу, если его нет. Только три случая.


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


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


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


                                1. divan0 Автор
                                  05.09.2017 11:11
                                  -2

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


                                  1. SirEdvin
                                    05.09.2017 11:20
                                    +1

                                    Ну да. И я смотрю проекты на python и отлично понимаю, как обрабатываются ошибки.


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


                                    1. divan0 Автор
                                      05.09.2017 11:24
                                      -2

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

                                      Вы не понимаете и оперируете какими-то концепциями в вакууме. Эта строчка вам даёт самое важное:


                                      • ошибка в этом месте будет обработана
                                      • эта ошибка останавливает дальнейшую работу функции
                                      • ошибка передается наверх как есть

                                      Этого уже более чем предостаточно чтобы понимать функцию, с которой вы работаете. Если вы хотите понять, как она обрабатывается выше — вы просто идёте выше и смотрите там. Но поинт в том, что всё это явно и ментальная модель программы строится на лету и быстро.


                                      Я пойду писать бот, который будет автоматически на ваши комментарии отвечать одним и тем же :)


                                      1. SirEdvin
                                        05.09.2017 11:29
                                        +2

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


                                        Эта строчка не дает вам самого важного. Понимания того, как именно программа поведет себя, когда вы вернете ошибку. А raise Exception дает.


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


                                        1. divan0 Автор
                                          05.09.2017 11:30
                                          -2

                                          у вас процедурная деформация

                                          Понятно.


                                          А если какой-то парень забыл

                                          Пусть девушка значит пишет.


                                        1. Crandel
                                          05.09.2017 11:35

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


                                          1. SirEdvin
                                            05.09.2017 11:38
                                            +1

                                            Да? А у меня собралось, и никаких усилий я не приложил.


                                            1. Crandel
                                              05.09.2017 11:44

                                              После того, как вы сознательно проигнорировали ошибку. А у меня проект упал, потому что где-то в глубине фреймворка пробрасывалось исключение и разработчик не знал про это и забыл сделать try/except. Это и называется явная обработка ошибок, в отличии от неявной. Хотя мне больше нравится Option тип в расте, чем обработка в Го. Но там и там это явно


                                              1. SirEdvin
                                                05.09.2017 11:55
                                                +1

                                                На мой взгляд, проблема "разработчик забыл сделать try/except" вполне равносильна "разработчик забыл прокинуть ошибку". Но поправить первый случай можно даже со стороны своего кода, а второй нет.


                                                Ну и да, монада Option тащит :)


                                            1. divan0 Автор
                                              05.09.2017 11:44
                                              -2

                                              у меня собралось, и никаких усилий я не приложил.

                                              А '_' сам себя написал, да? :) Вы фанат своего мнения, я смотрю.


                                              1. SirEdvin
                                                05.09.2017 11:52

                                                Я сделаю код реальнее, что бы вы мне поверили.


                                                1. divan0 Автор
                                                  05.09.2017 13:30
                                                  -2

                                                  Я сделаю код реальнее, что бы вы мне поверили.

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


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


                                                  1. SirEdvin
                                                    05.09.2017 14:03

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

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


                                                    Хотя мне кажется, что такой mute ошибки куда серьезнее, чем неиспользуемый импорт.


                                                    1. divan0 Автор
                                                      05.09.2017 14:12
                                                      -1

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

                                                      Да вам ток шоу надо режиссировать :) Вы компилятору явно приказали проигнорировать ошибку, еще и коммент для программиста оставили. С чего бы компилятору это не схавать? Ну вы тролль профессиональный, да уж.


                                                      1. SirEdvin
                                                        05.09.2017 14:13

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


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


                                                        1. divan0 Автор
                                                          05.09.2017 14:18
                                                          -1

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

                                                          Просто перестаньте писать бессмысленные комментарии на Хабре и сразу начнёт игнорировать. Это же в спецификации Go написано.


                                                        1. VolCh
                                                          05.09.2017 22:24
                                                          +2

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


                                                          1. SirEdvin
                                                            05.09.2017 22:38

                                                            А потом оторвать тому, кто так делает руки.
                                                            Ну и на самом деле, найти такое место довольно просто, по grep "catch Exception" в python, например.


                                                            А как найти описанный выше пример на golang?


                                                        1. 0xd34df00d
                                                          05.09.2017 23:31

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

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


                                      1. vintage
                                        05.09.2017 13:08
                                        +4

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


                                  1. 0xd34df00d
                                    05.09.2017 23:28

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


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


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


                    1. Falstaff
                      05.09.2017 05:06
                      +2

                      Вы меня превратно поняли; я не говорю, что исключения надо повсеместно похоронить и заменить тонной boilerplate. :) Я просто привёл пример того, что исключения — это не волшебное средство от сложности и "просто писать код" всё равно не получится. Они просто переносят сложность в другую плоскость — пишут за вас невидимые if (err != nil) { return err }. В каких-то задачах это приемлемо и желательно, в каких-то совсем наоборот, но я не знаю способа решить раз и навсегда, какие из задач какие. Думаю, что никто не знает, иначе бы мы тут не спорили.


                      1. SirEdvin
                        05.09.2017 08:26

                        Я плохо знаю C++, так что можете, пожалуйста, для меня подтвердить — там большинство ошибок же будет связано с невозможностью выделить или освободить память, а так же с отсутствием stdout?


                        1. Falstaff
                          05.09.2017 11:03
                          +1

                          stdout, нет, такого нет… Управление памятью — да, добавляет рисков, но на мой взгляд это не самая большая их доля, плюс современный идиоматичный код с умными указателями этому не так подвержен. Посмотрите внизу, где мы с vintage дискутируем — там пример неприятностей, которые не связаны с управлением ресурсами. Исключение может застать вас в процессе изменения данных, которые вы должны изменить консистентно (или не изменить вообще, если происходит ошибка).


                  1. vintage
                    05.09.2017 01:25
                    +1

                    void doMyJob() {
                        auto file = fopen( ... );
                        scope( exit ) file.close();
                        // работаем с файлом и не боимся исключений
                    }

                    Или даже так:


                    void doMyJob() {
                        scoped file = File( ... );
                        // работаем с файлом и не боимся исключений ведь файл будет закрыт при выходе из скоупа
                    }

                    Или вообще так:


                    void doMyJob() {
                        auto file = File( ... );
                        // работаем с файлом и не боимся исключений ведь файл будет закрыт, когда на него не останется ссылок
                    }


                    1. Falstaff
                      05.09.2017 04:54
                      +3

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


                      void doMyJob() {
                          auto file = File(...);
                          // работаем с файлом и не боимся исключений ведь файл будет закрыт, когда на него не останется ссылок
                          auto data = readSomeData(file);
                          writeRecordHeader(file);
                          auto record = processData(data);  // Бросает исключение.
                          writeRecordBody(file, record);
                      }

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


                      Пример с файлом утрированный и частный, поэтому давайте абстрактнее:


                      void UpdateRecord(Record* r, Data d) {
                        r->x = CalculateNewX(d);
                        r->y = CalculateNewY(d);
                      }

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


                      Ресурсы — это не самая большая проблема с исключениями; RAII поможет освободить память или закрыть файл. Проблема в том, что исключения — это невидимые глазу if (...) { return; } в вашем коде, и если вы их не учитываете, то запросто можете оставить мир в некоем фатально видоизменённом состоянии после ошибки.


                      1. vintage
                        05.09.2017 07:27
                        +1

                        Но управление ресурсами — это далеко не единственное место, где исключения привносят сложность.

                        Нет там никакой сложности в современном языке.


                        И всё потому, что функцию processData() писали не вы, и кто знал, что она бросает исключение.

                        В языке с исключениями все функции их могут бросать. Это аксиома. В любом случае ваш код должен выглядеть так:


                        void doMyJob() {
                            auto file = File(...);
                            auto data = readSomeData(file);
                            auto record = processData(data);  // Бросает исключение или взрывает компьютер.
                        
                            auto newFile = tmpfile();
                            newFile.writeRecordHeader();
                            newFile.writeRecordBody(record);
                        
                            file.remove();
                            newFile.rename( file.name );
                        }

                        Пример с файлом утрированный и частный, поэтому давайте абстрактнее:

                        Ваш код при многопоточном доступе точно так же огребёт проблем. Кроме того, как вы будете восстанавливать консистентность, если уже стёрли x?


                        исключения — это невидимые глазу if (...) { return; } в вашем коде

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


                        1. Falstaff
                          05.09.2017 10:56
                          +1

                          Нет там никакой сложности в современном языке.

                          Возможно. Но вокруг тонны legacy кода, не готового к RAII, и с ним приходится как-то жить.


                          В языке с исключениями все функции их могут бросать. Это аксиома. В любом случае ваш код должен выглядеть так:

                          Именно. :) Выше я писал о том, что исключения предполагают определённый стиль мышления, и вы избавили меня от необходимости это иллюстрировать. Да, в языке с исключениями все функции под подозрением, и это вырабатывает у вас навык писать в таком стиле — группировать работу функций в собственно работу, и commit фазу, где закрепляются результаты этой работы. Это как раз и есть способ обеспечить strong exception guarantee. Но сам по себе этот навык не вырабатывается, это и есть та сложность и та когнитивная нагрузка, которую несут исключения.


                          Ваш код при многопоточном доступе точно так же огребёт проблем. Кроме того, как вы будете восстанавливать консистентность, если уже стёрли x?

                          При чём здесь многопоточность? В этой функции нет глобального состояния. (Если что, запись у каждого потока своя, мы это не видим, да и не про то речь.) А консистентность — вы ведь уже сами продемонстрировали выше, в коде. Консистентность приходится не восстанавливать, а просто не нарушать — строить функцию так, что сначала идёт работа, а потом commit phase, где результаты работы (причём, если нужно strong exception guarantee, то там всё должно быть nothrow) присваиваются x. Конечно, то же самое вы будете проделывать с кодами ошибок, но в том-то вся и суть, что в отсутствие исключений вы видите явно, какая функция может упасть, а вот с исключениями они все под подозрением, и вам приходится программировать защитно, вот в таком стиле.


                          Нет там никаких if-return. Прелесть исключений в том, что вы за них платите лишь при установке обработчика и раскрутке стека.

                          Оставляя в сторону ту самую когнитивную нагрузку, которую вы платите за кучу скрытых нелокальных goto в коде… Да, нагрузка времени исполнения выше у if'ов. Но откуда мнение, что это везде настолько критично? Плюс я уже приводил выше пример — за исключения я плачу ещё и памятью во время раскрутки стека. В embedded, если вы используете RTOS, это здорово портит жизнь и (в моей практике) заставляет (именно в embedded) отказаться от исключений — при раскрутке одномоментно используется очень много стека, и стек каждой задачи должен быть достаточно большим, чтобы быть к этому готовым, а задач может быть много. Прелести исключений не универсальны, и за них приходится платить.


                          1. vintage
                            05.09.2017 13:52
                            +1

                            это вырабатывает у вас навык писать в таком стиле — группировать работу функций в собственно работу, и commit фазу, где закрепляются результаты этой работы

                            Как я, надеюсь, показал это хороший навык, независимо от поддержки в языке исключений.


                            В этой функции нет глобального состояния.

                            Есть внешнее состояние, которое может оказаться и глобальным.


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

                            В Go уже завезли Thread Local Storage? Впрочем, если CalculateNewX снимет горутину с ядра, то следующая горутина увидит запись в неконсистентном состоянии.


                            в отсутствие исключений вы видите явно, какая функция может упасть

                            Вы мне покажите лучше функцию, которая гарантированно не может кинуть панику :-)


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

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


                            за исключения я плачу ещё и памятью во время раскрутки стека

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


                            1. Falstaff
                              05.09.2017 15:23
                              +1

                              В Go уже завезли Thread Local Storage? Впрочем, если CalculateNewX снимет горутину…
                              … которая гарантированно не может кинуть панику :-)

                              Извините если я у вас случайно создал впечатление, что мы обсуждаем Go. :) Мы обсуждаем исключения. Я на Go в общем и целом не пишу (так, потыкал для общего развития), поэтому не буду развивать тему паники (а чем она не исключение?) и TLS (что вам мешает просто не передавать эти данные во много горутин/потоков? если передаёте, то уж наверное это делаете осознанно и не каждую минуту). В общем, мы не про Go и уж точно не про shared state. Для простоты представьте что у нас один поток, проблема exception safety от этого никуда не денется.


                              Как я, надеюсь, показал это хороший навык, независимо от поддержки в языке исключений.

                              Не хочу вас расстраивать — но, нет, не показали. Вот кстати, вы сейчас клеймили if'ы за то, что они сбрасывают конвейер (я бы не согласился, кстати — во-первых есть предсказание ветвления, во-вторых ему ещё и помочь можно, указав наиболее вероятную ветвь). Но возьмите такой пример:


                              void Update(Record* r) {
                                 GetNewDataX(r->x, ...);  // x - это массив.
                                 GetNewDataY(r->y, ...);  // y - тоже.
                              }

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


                              void Update(Record* r) {
                                 // Тут выделяем массив temp.
                                 GetNewDataX(temp, ...);
                                 GetNewDataY(r->y, ...);
                                 Copy(r->x, temp);  // nothrow
                              }

                              Представьте, что x и y — массивы размером в мегабайт каждый. Внезапно, необходимость учитывать возможность выброса исключений вынудила вас выделять мегабайт памяти и тратить время на его копирование. Вы только что спустили в трубу гораздо больше тактов процессора, чем вы сэкономили на if'ах. Функция GetNewDataX() на самом деле не бросает исключения, но поскольку все в списке подозреваемых, пришлось написать неэффективный код.


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

                              Вы меня, кажется, не поняли. Под защитным стилем я имел (что и написал) не то, где вы размещаете try-catch, а то, как вы организуете работу функции. Если у вас вылетело исключение при частично модифицированных данных, то это не имеет отношения к тому, что вы ловите и на каком уровне — вызывающая процедура получит неконсистентный результат. И поэтому (как вы сами и продемонстрировали) вы переписываете свой код определённым методом. (И ещё раз — извините, я не "делаю в Go", не переходите на личности.)


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

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


                              1. vintage
                                05.09.2017 15:48

                                Для простоты представьте что у нас один поток, проблема exception safety от этого никуда не денется.

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


                                во-первых есть предсказание ветвления, во-вторых ему ещё и помочь можно, указав наиболее вероятную ветвь

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


                                GetNewDataX() не возвращает кода ошибки (и исключений нет, поэтому неявно вернуть тоже не может). Поэтому функцию использовать безопасно.

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


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

                                Специфическим условиям могут быть специфические решения. Не идиомы ту пинать надо.


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

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


                                1. Falstaff
                                  05.09.2017 17:14

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

                                  А вы всегда пишете thread-safe код, вне зависимости от? То есть вы всегда исходите из предположения, что ваши входные данные всегда может кто-то щупать из другого потока? Извините, но… мне очень сложно заставить себя в это поверить. Учтите, что в таком случае просто сделать работу а потом обновить результат недостаточно. Даже простое копирование может наложиться на доступ из другого потока. Вы каждый кусок данных окружаете защёлками, каждый флаг делаете атомарным? В яве, например, пожалели что сделали старые Vector и Hashtable synchronized, потому что оверхед большой, а потокобезопасность нужна редко. Вы же только что превозносили исключения за то, что они позволяют вам не платить за то, что не используете, а теперь сами говорите, что хотите заплатить за потокобезопасность (которая вам пока не нужна). Я удивляюсь.


                                  Вообще, строго говоря, я не знаю, откуда тут вообще аргумент про многопоточность. Организация кода для exception safety не даёт потокобезопасность каким-то магическим образом, и наоборот — код может быть потокобезопасным, но не exception safe.


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

                                  Вы тратите сотни (или тысячи, если в куче) тактов на выделение и копирование памяти, когда вам надо сделать временное хранилище результата и обеспечить exception safety, и для вас это приемлемо, а промах предсказателя ветвлений — трагедия. Про защиту от конкурентного доступа я уже молчу.


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

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


                                  Специфическим условиям могут быть специфические решения. Не идиомы ту пинать надо.

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


                                  За меня об этом думают разработчики компиляторов. <...> Компилятор не то что условия, а даже собственно вызова может не вставить, если посчитает нужным.

                                  Тогда о чём говорить? Компилятор и ветвления умеет оптимизировать — вы же не проверяете, сколько ветвлений он выбрасывает, сколько переставляет, угадывая, какая из ветвей более вероятна, что ему profile-guided optimization нашёптывает. Вообще, мир, в котором ошибки предсказания ветвления были бы самым значимым фактором в оптимизации программ, был бы поистину прекрасен.


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


                                  1. MikailBag
                                    05.09.2017 18:53

                                    Функция принимает типизированный массив фиксированного размера, и компилятор бы её просто не скомпилировал, если бы был выход за границы?

                                    Как вы предлагаете это (проверку) реализовать?


                                    1. Falstaff
                                      05.09.2017 19:41

                                      Передать в функцию не голый указатель, а что-то наподобие std::array<T, N>? Если вы попытаетесь передать массив другого размера, это будет уже другой тип.


                                      Нет, я не говорю о том, что сама реализация потом не попытается записать что-то в память за пределами массива. Во всяком случае в C/C++ вам никто не помешает, но и вопрос "а что если эта функция сделает что-то страшное" тогда не имеет смысла. Тогда всё взорвётся. Или функция вернёт мусор и всё взорвётся потом. Или она вернёт мусор и всё продолжит как-то работать. Но она в любом случае не сможет вернуть ни код ошибки ни исключение, потому что она сама не знает, что в ней баг. В коде нам приходится исходить их того, что функция следует контракту.


                                      1. 0xd34df00d
                                        05.09.2017 23:48

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


                                        1. Falstaff
                                          05.09.2017 23:59

                                          Во-первых, вы можете упереться в ulimit. Во-вторых, массив может выделяться в куче, а в самом классе будет только указатель. (Да, std::array<> выделяет статически, но в общем случае вы этого не знаете.)


                                          1. 0xd34df00d
                                            06.09.2017 00:38

                                            А, ну если в куче, то да.


                                            Но тогда можно и про дешёвую nursery area, пулы и прочие вещи пофантазировать.


                                            1. Falstaff
                                              06.09.2017 01:44
                                              +1

                                              Мы тут всё обсуждаем в контексте фантастического выигрыша в скорости от того, что мы избавились от if (err == nil) в коде. :) То есть хорошо бы что-нибудь дешевле нескольких cmpq $0, N(%rsp); jne on_error;. :)


                                              1. 0xd34df00d
                                                06.09.2017 01:46
                                                -1

                                                Выигрыш в скорости скорее будет оттого, что я сэкономлю порядком времени на набивании и поддержании всех этих if (err == nil) и быстрее перейду к профилированию.


                                    1. 0xd34df00d
                                      05.09.2017 23:48
                                      -1

                                      Есть языки с зависимыми типами, где это можно закодировать, собственно, в типе, но обсуждать завтипы в треде про Go, JS и C++ несколько смешно, как по мне.


                                    1. SirEdvin
                                      05.09.2017 23:49

                                      Как вы предлагаете это (проверку) реализовать?

                                      Шаблоны в C++ умеют делать такие страшные вещи, если не ошибаюсь.


                                    1. vintage
                                      06.09.2017 08:49

                                      auto doMyJob( int[3] data ) {
                                          return data[4]; // Compilation Error: array index 4 is out of bounds data[0 .. 3]
                                      }


                                      1. MikailBag
                                        06.09.2017 19:28

                                        void do(int[3] data){
                                             int x = system("node -c 'process.exit(5)'");
                                             data[x]
                                        }


                                  1. vintage
                                    05.09.2017 19:32

                                    Я стараюсь вносить изменения атомарно — это хорошая практика из которой уже вытекает и "exception safety" и "thread-safety" и "debug-friendly". D по умолчанию хранит все данные в TLS, а чтобы расшарить данные между потоками — нужно сделать их синхронизированными, что включается добавлением всего одного ключевого слова. Данные я не копирую без нужны, ведь есть COW и move.


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


                                    Вообще, по теме могу предложить почитать: https://habrahabr.ru/post/280378/


                                    1. Falstaff
                                      05.09.2017 20:01

                                      Я не совсем вас понял, и я недостаточно хорошо знаю D, чтобы понять специфику. Вот мы исходим из того, что ваш аргумент — структуру — может щупать другой поток. Вы сначала сказали, что многопоточность может вкрасться в любой точке функции, и надо её делать thread safe, а теперь вы говорите что в D всё в TLS и никаких общих данных нет, если вы сами явно не скажете. И как атомарность изменений (в контексте защиты от конкурентного доступа) помогает с exception safety, если исключения поднимаются вашим же потоком, то есть никак не затрагивают многопоточность? В середине изменения synchronized объекта у вас точно так же может вылететь исключение. Тут вам нужна уже другая атомарность — не в плане защиты от одновременного доступа, а в транзакционном плане.


                                      Ну и про функцию — а как вы вообще собираетесь учитывать ошибки разработчика? Мы сейчас говорим об исключениях, заметьте. Вы мне возразили — как же можно, функцию вызвали, кода ошибки она не возвращает, говорит что хорошая, но внутри баг и она делает страшные вещи. Какая в таком случае разница с исключением? Да, в функции баг, но она сама об этом не знает, и потому не вернёт ни исключение ни код ошибки. Вы думали, что сливание паролей злоумышленникам обязательно сопровождается исключениями? Она просто вылезет за пределы, и тогда может произойти всё что угодно, но сама функция об этом не догадается и не вставит ни throw ни if (...). Мы можем судить о функции только по контракту.


                                      За ссылку спасибо — почитаю, хотя я D никогда не ковырял, да и в Go в общем-то не силён.


                                      1. vintage
                                        06.09.2017 08:36

                                        Вы сначала сказали, что многопоточность может вкрасться в любой точке функции, и надо её делать thread safe

                                        Ну, это в C и Go так, если функция работает с внешней структурой.


                                        И как атомарность изменений (в контексте защиты от конкурентного доступа) помогает с exception safety

                                        Если возникло исключение, то до атомарного изменения (одного машинного слова, например, ссылки на данные) дело не дойдёт.


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

                                        Так она только такая и есть. Атомарное изменение для любого наблюдателя происходит либо целиком, либо не происходит вовсе. Если мы будем временно переводить объект в неконсистентное состояние, то мы теряем возможность восстановления в случае паники.


                                        Ну и про функцию — а как вы вообще собираетесь учитывать ошибки разработчика?

                                        В том-то и дело, что никак. Именно поэтому вы не сможете написать такую функцию, которая гарантированно никогда не паникует. Исключения дают единый механизм реакции на исключительные ситуации. Будь то, пользовательские исключения или системные.


                                        Она просто вылезет за пределы, и тогда может произойти всё что угодно

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


                                        1. Falstaff
                                          06.09.2017 13:46

                                          Ну, это в C и Go так, если функция работает с внешней структурой.
                                          Если возникло исключение, то до атомарного изменения (одного машинного слова, например, ссылки на данные) дело не дойдёт.

                                          То есть вы для любых входных данных делаете так, что изменение их происходит атомарно, инструкцией с барьером. Вопрос — как? Вот предположим, что вам передали объект. У него есть метод SetX() и метод SetY(). Или даже просто два разных поля, которые вам предстоит изменить. Вы не можете записать эти два поля атомарно (в значении слова "атомарно", которое вы используете, которое вас защищает и от исключений, и от других потоков). Какие ваши действия в таком случае?


                                          Так она только такая и есть. Атомарное изменение для любого наблюдателя происходит либо целиком, либо не происходит вовсе.

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


                                          void Update(Record* r) {
                                             EnterCriticalSection();
                                             GetNewDataX(r->x, ...);  // x - это массив.
                                             GetNewDataY(r->y, ...);  // y - тоже.
                                             LeaveCriticalSection();
                                          }

                                          Отлично, с точки зрения других потоков r изменяется атомарно. Но этот код всё равно не exception safe, потому что GetNewDataY() может бросить исключение.


                                          void Update(Record* r) {
                                             // Тут выделяем массив temp.
                                             GetNewDataX(temp, ...);
                                             GetNewDataY(r->y, ...);
                                             Copy(r->x, temp);  // nothrow
                                          }

                                          Этот код даёт strong exception guarantee. Но он ни разу не защищён от изменения данных со стороны. Да даже невинная Copy() может наложиться на операцию записи другим потоком, и у вас будут смешанные данные.


                                          Видите? Мы защищаемся от двух разных вещей двумя разными методами, это разная атомарность. (И кстати, первый вариант всё равно не даёт вам защиту от многопоточности, потому что некий поток изменит вашу запись после критической секции и результат работы функции просто потеряется. Какой физический смысл вообще у того, чтобы защищать r от параллельного доступа в этой функции? Можете объяснить, зачем это делать?)


                                          В том-то и дело, что никак. <...> Исключения дают единый механизм реакции на исключительные ситуации. Будь то, пользовательские исключения или системные.

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

                                          Я не понимаю. При чём здесь исключения? Как поддержка исключений (сама по себе) магически даст вам возможность отловить выход за границы массива или доступ по нулевому указателю? Исключения должны где-то выбрасываться; коды ошибок — где-то возвращаться. В случае ошибки разработчика этих мест там нет. Вы, возможно, привыкли к языкам с bounds checking, но во-первых это совершенно ортогонально исключениям (вы в принципе можете иметь проверку границ и без исключений), а во-вторых это не панацея от багов.


                                          Возьмите код на С++ — там есть исключения, но при этом функция, которую вы вызываете, может радостно пройтись по чужой памяти, получить доступ к нулевому указателю (или указателю с мусором), и при этом никаких исключений выброшено не будет. Вы или получите мусор в памяти, или программа упадёт (и, да, грохнет весь сервер), но исключения вам не будет. Вы можете посоветовать стать ёжиком и использовать язык с bounds checking, но и это не защитит вас от ошибок разработчика — во-первых они не сводятся к ошибкам памяти, а во-вторых, и в этих языках (возьмём Java для примера) вы не можете гарантировать, что охочий до оптимизации программист не сделал реализацию через JNI или не использовал Unsafe, и теперь функция может пройтись по любой памяти, а исключения вы всё равно не получите. Исключения — это всего лишь один из способов пробросить ошибку наверх, но у вас нет гарантии, что все ошибки будут сопровождаться исключениями. Они не дают вам защиты от багов. Язык — может некоторую защиту дать, но это ортогонально способу доставки сообщений о тех багах, которые он поймал.


                                          1. vintage
                                            06.09.2017 14:16

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

                                            Барьеры-то тут при чём? Они лишь упорядочивают операции.


                                            У него есть метод SetX() и метод SetY()

                                            У него будет метод Update() или я просто создам новый объект с нужным состоянием.


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


                                            1. Falstaff
                                              06.09.2017 14:32

                                              У него будет метод Update() или я просто создам новый объект с нужным состоянием.

                                              Это не ваш объект. Вы не можете его менять, он вам даден сверху. Или опять "мышки, станьте ёжиками"? А в методе Update() не надо будет заботиться об атомарности? Вообще, вы не ответили ни на один из моих вопросов по сути. Я так и не узнал, что вы в действительности хотели сказать. Притянули за уши многопоточность — но не смогли объяснить, зачем она вам нужна. Заявили, что накопление результатов работы и атомарное изменение выходных данных — всегда хорошая привычка, но на контраргументы не ответили. Заявили, что ветвления портят вам производительность — и тут же сказали, что вы в общем-то никогда и не измеряли, пусть, мол, разработчики компиляторов заботятся. То есть в общем-то ничего и не сказали.


                                              Ну, я не прессую — бог с ним, останемся при своих. Спасибо за беседу; пардон если где-то горячился.


                                          1. 0xd34df00d
                                            06.09.2017 20:37

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


                                            1. Falstaff
                                              06.09.2017 21:51

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


                1. 0xd34df00d
                  05.09.2017 23:24

                  Явный return явно показывает, что и где из функции может возвращаться, и по сигнатуре функции видно, какие у неё ошибки.


                  Правда, опять же, это не случай Go. Где-то тут монады, конечно, плавают, Maybe всякие, Either, там и сразу всё видно, и цепочки if'ов писать не нужно, и компилятор может дешугарить это во вполне эффективный код, но в Go этого нет.


                  1. SirEdvin
                    05.09.2017 23:28
                    -1

                    Явный return явно показывает, что и где из функции может возвращаться, и по сигнатуре функции видно, какие у неё ошибки.

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


                    1. 0xd34df00d
                      05.09.2017 23:40

                      Поэтому я и написал, что это не случай Go.


                      Впрочем, вам и в случае исключений написать catch (...) никто не мешает, и в случае монадок написать какой-нибудь fromRight. Просто такие вещи грепать легче.


      1. SuperPaintman
        04.09.2017 17:47
        +2

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

        Вероятнее всего, для вас это непонятно потому-что вы, возможно, не знакомы с async / await API и промисами в JS. Если произойдет ошибка в асинхронной функции, она свалится в ближайший .catch() или в unhandledRejection


        Собственно сниппет


        (async function () {
        })()
          .catch((err) => {
            console.error(err);
        
            process.exit(1);
          });

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


        try { } catch (err) { } конструкция гораздо более громоздка, голословна, и при этом менее ясна, чем if err := thingB(); err != nil {… }. 5 строк против 3, при нулевых бенефитах в данном случае, и еще и спрятанной магией передачи ошибки.

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


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

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


        1. divan0 Автор
          04.09.2017 17:52
          -3

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

          А если хотите?


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

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


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

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


          1. raveclassic
            05.09.2017 11:46
            +1

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


            1. vintage
              05.09.2017 13:58
              +1

              Потому, что для этого нужны дженерики, а авторы Го не осилили их реализовать, поэтому постановили, что "дженерики не нужны*".


              * кроме пары стандартных.


              1. divan0 Автор
                05.09.2017 14:15
                -1

                Да печаль совсем:


                1. vintage
                  05.09.2017 14:31
                  +3

                  Уж простите, я не евангелист всех остальных языков, так что текстом:


                  Go: сидит дитетка, лепит куличики из песка: "Да я какой хош небоскрёб так сделаю, нужно только побольше куличиков".


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


                  1. divan0 Автор
                    05.09.2017 14:33
                    -1

                    Хорошая фантазия :) Далека от истины, но хороша.
                    Особенно понравилось про «любой другой язык». Прямо все хороши, кроме Go, да.


                    1. raveclassic
                      05.09.2017 19:28
                      +1

                      Ну почему, про куличики прям в яблочко.


                  1. andreysmind
                    05.09.2017 18:57
                    +1

                    Расмус Лердорф и Брендон Айк (из самых известных создателей %любых других продуманных языков%) внимательно тебя слушают. :)


                    1. raveclassic
                      05.09.2017 19:30

                      JS продуманный язык? Я сплю?


                      1. raveclassic
                        05.09.2017 20:03
                        +1

                        А :)


                    1. vintage
                      05.09.2017 19:49

                      Детство у них тяжёлое, но сейчас они уже ничего.


                  1. CuredPlumbum
                    05.09.2017 22:34
                    +1

                    1. SirEdvin
                      05.09.2017 23:44
                      +1

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


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


                      1. divan0 Автор
                        05.09.2017 23:51
                        -3

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


                        1. SirEdvin
                          06.09.2017 06:57
                          -1

                          Эта ниша уже занята вам, мне вас не одолеть :(


                      1. CuredPlumbum
                        06.09.2017 07:54
                        +1

                        Я не о том, что они открывали в свободный доступ. Процитирую:

                        About a year ago, we decided to migrate our performance-critical backends from Python to Go to leverage better concurrency support and faster execution speed.


                        1. SirEdvin
                          06.09.2017 14:00

                          Потому что раньше медленные места с Python переписывали на C/C++, а теперь взяли Golang?
                          Ну да, я уже говорил, что golang отличная замена C.


                    1. vintage
                      06.09.2017 08:58
                      +1

                      Дропбокс — яркий пример успешного бизнеса построенного на довольно простой в реализации идее. Вы посмотрите сколько конкурентов у дропбокса, а сколько у, например, SAP ERP.


                      1. CuredPlumbum
                        06.09.2017 10:19

                        И?..

                        Предлагаете обсудить ABAP? Знакомы с ним?


                        1. vintage
                          06.09.2017 11:35

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


                          1. CuredPlumbum
                            06.09.2017 11:54

                            И всё же: что вы скажите за ABAP?


                            1. vintage
                              06.09.2017 12:03

                              Ничего, я его не курил.


              1. raveclassic
                05.09.2017 19:31
                +1

                Я с го вообще никак, поэтому сейчас меня это повергло в шок.
                Другими словами, "то есть как нет дженериков" o_o


                1. SirEdvin
                  05.09.2017 23:43

                  Ну вот так. Авторы заявили, что шаблонные типи усложняют код. Поэтому их в языке и нет.


                  1. divan0 Автор
                    05.09.2017 23:56
                    -2

                    Ну вот так. Авторы заявили, что шаблонные типи усложняют код. Поэтому их в языке и нет.

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


                    1. SirEdvin
                      06.09.2017 06:56

                      То есть вот этот человек не прав? Или вот эта статья?


                      1. divan0 Автор
                        06.09.2017 10:08
                        -1

                        То есть вот этот человек не прав?

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


                        1. msts2017
                          06.09.2017 10:51
                          +1

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

                          Таким образом ввод generics сильно усложнит язык — как реализацию, так и использование.

                          Дженерики невероятно сложны как по своей семантике, так и по реализации

                          или не так понял? как надо было понять?


                          1. divan0 Автор
                            06.09.2017 11:09

                            То что усложнит, это любому понятно, надеюсь. Но:
                            а) дженерики это концепт, а шаблонные типы — это реализация
                            б) в Go нет дженериков, потому что авторы Go не видят способа их реализовать без того, чтобы не усложнить язык (не только код)
                            в) авторы Go не отказывались от дженериков, наоборот только за, если все специалисты Хабра расскажут, как и правильно сделать чтобы потом запрос в гугл «language X generics sucks» при X=Golang не выигрывал конкурс Generics Sucks Contest.


                            1. msts2017
                              06.09.2017 11:18
                              +1

                              Чет я не понял в каком месте то что написал SirEdvin противоречит тому что вы.


                              1. divan0 Автор
                                06.09.2017 11:27
                                -1

                                Он свёл это к «шаблоны усложняют код, поэтому в Go нет дженериков». Усложнение языка это не «усложнить код» — это усложнение рантайма, сборщика мусора, процесса компиляции, когнитивной нагрузки на программиста, тулинга, грамматики и много чего ещё. Шаблоны != дженерики, это лишь один из вариантов. Ну и если уж на то пошло, в Go есть дженерики (типонезависимые функции), но пользователи создавать свои не могут. Плюс, целый класс тех задач, которые решаются «шаблонами» в Go решаются интерфейсами.

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


                                1. vintage
                                  06.09.2017 11:41
                                  +1

                                  Касательно шаблонов..


                                  усложнение рантайма,

                                  Нет.


                                  сборщика мусора

                                  Нет.


                                  процесса компиляции

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


                                  когнитивной нагрузки на программиста

                                  Она уменьшится, ибо ему придётся меньше писать и читать generic кода.


                                  тулинга

                                  Незначительно.


                                  грамматики

                                  Незначительно.


                                  и много чего ещё

                                  Чего ещё?


                                  1. divan0 Автор
                                    06.09.2017 12:12
                                    -1

                                    Касательно шаблонов.
                                    Нет.
                                    Нет
                                    Незначительно.
                                    Незначительно.

                                    Спасибо за доступное объяснение и хорошую аргументацию, всегда приятно послушать мысли умных людей. Теперь понятно.


                                    1. vintage
                                      06.09.2017 12:21
                                      +1

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


                                      Вы выдвинули тезис о каком-то значительном усложнении всего — вам его и доказывать.


                                1. rraderio
                                  06.09.2017 11:51
                                  +1

                                  в Go есть дженерики (типонезависимые функции

                                  а это не усложнение рантайма, сборщика мусора, процесса компиляции, когнитивной нагрузки на программиста, тулинга, грамматики и много чего ещё?


                                  1. divan0 Автор
                                    06.09.2017 12:10
                                    -1

                                    а это не усложнение рантайма, сборщика мусора, процесса компиляции, когнитивной нагрузки на программиста, тулинга, грамматики и много чего ещё?

                                    Слово trade-off слышали? Или у вас всё бинарно через "нужен/не нужен"?


                                    1. rraderio
                                      06.09.2017 12:23
                                      +1

                                      Хм, и почему то что сделали авторы go это trade-off, а то что пишу я это бинарное мышление?


                                1. msts2017
                                  06.09.2017 11:51
                                  +1

                                  Ладно проехали, я остался при первоначальном впечатлении, никакого противоречия не увидел.


                1. divan0 Автор
                  05.09.2017 23:48
                  -1

                  Ещё чего нет:
                  — классов
                  — эксепшенов
                  — наследования
                  — тернарного оператора
                  — многих способов сделать одно и то же
                  — алгебраических типов
                  — арифметики поинтеров
                  — ручного освобождения памяти

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


                  1. raveclassic
                    06.09.2017 00:33
                    +1

                    Вы уж простите, но удобство программирования на статически типизированных языках в 2017 так или иначе упирается либо в наличие классов, интерфейсов и наследования, либо в алгебраические типы и типы высших порядков (HKT). Ни того, ни другого, ни, уж тем более, дженериков (а как можно жить писать переиспользуемый код без них, я вообще не представляю) и в помине нет. И что я вижу — так это стокгольмский синдром на лицо.


                    Я терпеть не могу эксепшены, и, может быть, в следующей жизни готов помириться с фантастическими if err != nil по всему коду, но я вас прошу, не пытайтесь тут продать язык, в котором якобы "специально" отказались от нереально удобных вещей, использующихся десятилетиями, в угоду мнимому субъективному удобству и понижению порогу входа. Последнее вообще рассмешило, вон в пхп тоже низкий порог входа.


                    1. divan0 Автор
                      06.09.2017 10:18
                      -1

                      Ха-ха, прощаю, знаете сколько я такого наслушался за последние 4 года? Вот этих гневных бравад про «я знаю точно, что удобно в языках программирования, а эти неучи из Го, пусть даже создавшие Unix, ничего не понимают в жизни, и не пытайтесь мне доказать, что они не идиоты!». Прям обнять хочется и успокоить. Вот уж где стокгольмский синдром, это точно. :)


                      1. raveclassic
                        06.09.2017 13:07
                        +1

                        знаете сколько я такого наслушался за последние 4 года

                        Ну а я бы сделал выводы.


                        И это не гневные бравады, что вы. Гневные бравады обычно у тех, кто что-то пытается защитить. Я же ничего не защищаю, а просто указываю, что прогресс в области программирования достиг определенных вещей, выкидывать которые, прикрываясь аргументами "ой сложно" — глупо.


                        Про неучей я ничего не говорил, видимо вам уже мерещится. И я вам ничего не доказываю, ни что они неучи, ни что идиоты, это вы всё сами.


                        Почитайте про этот чудесный синдром — вас чего-то лишают, а вы считаете, что это хорошо.


                        1. divan0 Автор
                          06.09.2017 15:00
                          -1

                          Ну а я бы сделал выводы.

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


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

                          Именно поэтому меня и бесят тут высказывания троллей, которые берут такой многогранный вопрос, упрощают его до фраз "авторы Go сказали 'ой сложно' и не стали делать дженерики", которые разжигают в других неадекватные реакции.


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


                          Почитайте про этот чудесный синдром — вас чего-то лишают, а вы считаете, что это хорошо.

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


                          1. SirEdvin
                            06.09.2017 15:07

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

                            Что? Вы вообще когда-то видели другие языки помимо golang? Или для вас interface{} образец читабельности? Дженерики можно обвинить в чем угодно, но в ухудшении читабельности их обвинить никак нельзя. У меня такое чувство, что вы пришли из С99 и теперь рассказываете, как все в go отлично. А тем временем на дворе 2к17, однако.


                            Именно поэтому меня и бесят тут высказывания троллей, которые берут такой многогранный вопрос, упрощают его до фраз "авторы Go сказали 'ой сложно' и не стали делать дженерики", которые разжигают в других неадекватные реакции.

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


                            Но черт возьми, от этого не стоит писать "дженериков в golang нет, потому что они не нужны". Они объективно нужны, потому что открывается любой более менее большой проект на go, делается grep и открывается прекрасный мир interface{}. И то, что создатели golang не смогли в дженерики является единственной причиной того, что их в языке нет. Никто не говорит "ахаха, лалки не смогли", потому что задача в самом деле сложная. Но делать из этого религию в духе "дженерики не нужны", глупо.


                            1. divan0 Автор
                              06.09.2017 15:18
                              -1

                              Вы вообще когда-то видели другие языки помимо golang?

                              Да.


                              Или для вас interface{} образец читабельности?

                              interface{} это empty interface, мы говорим про интерфейсы в целом. Вы сначала разберитесь в теме, а потом пишите свой 200-й бессмысленный комментарий.


                              Но делать из этого религию в духе "дженерики не нужны", глупо.

                              Религию эту придумали вы, и вы же её своими комментариями и популяризируете. Вы даже не хотите разобраться в теме, поэтому повторюсь:


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

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


                              И еще раз — если вы настолько свято верите, что без привычных вам дженериков жизни нет и быть не может и это святое и ежедневная необходимость — напишите Experience Report, объясните конкретную проблему, которую вы решали, и как отсутствие дженериков стал вам на пути. Объясните насколько это серьезная проблема, чтобы авторы Go вообще могли оценить, какое решение могло бы подойти лучше.


                              А вот эти религиозные 300 комментариев, каждый из который сквозит незнанием темы, это любой школьник может.


                              1. SirEdvin
                                06.09.2017 15:24

                                interface{} это empty interface, мы говорим про интерфейсы в целом. Вы сначала разберитесь в теме, а потом пишите свой 200-й бессмысленный комментарий.

                                А я думал вы знаете Go. interface{} это еще способ эмулирования дженериков, как это делает Java, но вручную. Как и большинство вещей в go.


                                дженерики в Go есть, кроме определенных видов

                                Ну да. Generic в go — это interface{}. И да, это конечно же отличный дизайн, как и все в go.


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

                                Потому что он заменил C? Ну да, это все знают.


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

                                Невозможного ничего нет, пока есть приведение к interface{} и обратно, но попробуйте написать какой-то универсальный контейнер, например, монаду Maybe. И поиспользовать ее на go.


                                1. divan0 Автор
                                  06.09.2017 15:28
                                  -1

                                  interface{} это еще способ эмулирования дженериков,
                                  Ну да. Generic в go — это interface{}

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


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

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


                                  1. SirEdvin
                                    06.09.2017 15:32
                                    +1

                                    Docker решает? Там вот используются функции, которые принимают interface{}.
                                    Или вам нужно еще десяток проектов накидать, что бы вы поняли, то, что дошло до создателей языка?


                                    1. divan0 Автор
                                      06.09.2017 15:35
                                      -1

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


                                      1. SirEdvin
                                        06.09.2017 15:38
                                        -1

                                        Ах, ну да. Вы не можете следить за стеком вызовов, я и забыл.


                                        Вот такой у нас тут был pipeline:


                                        • Дженерики не нужны
                                        • Еще как нужны, просто вместо них используется ущербный вариант через interface{}
                                        • Нет, это ничего не нужно и вообще без него все отлично
                                        • Ну вот нет, напишите такую монаду
                                        • Ох нет, это выдуманная проблема, а вот вы напишите реальный проект
                                        • Docker реальный проект?
                                        • И вот мы тут.


                                  1. VolCh
                                    07.09.2017 22:23
                                    +2

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

                                    А можете привести пример такой реальной задачи на Go? Ну там бухгалтерия и склад какой-нибудь или АвтоКАДа? Может CRM, ERP? Игрушка полноценная? Что-то, что решает реальные задачи, а не служит инфраструктурой?


                                    1. SirEdvin
                                      07.09.2017 22:38

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


                                      И еще одна, которая попытаеться повторить удачу odoo (раньше openerp), но с таким синтаксисом они далеко не уедут.


                                    1. divan0 Автор
                                      07.09.2017 22:56

                                      Ну там бухгалтерия и склад какой-нибудь или АвтоКАДа? Может CRM, ERP? Игрушка полноценная? Что-то, что решает реальные задачи, а не служит инфраструктурой?

                                      Смотрите, есть различные ниши — например десктопное приложение это не тоже самое, что консольная утилита, а firmware для embedded устройства это не тоже самое, что массивная распределённая кластерная система. Вы сейчас пытаетесь сказать, что одни ниши — это "реальные проблемы", а другие ниши (сервера, в частности) — это "инфраструктура". Но это, понятное дело, очень неверный взгляд на вещи, я бы даже сказал, устаревший. Сам помню то время, когда основная масса писавшегося софта — это были десктопные программы и игрушки. Но мы же в 2017, в мире облаков, кластеров, распределенных систем, микросервисов и блокчейна. Новые языки и технологии больше ориентированы на эти ниши, а не на умирающие вроде десктопного софта. Ну а Go так и вообще прямым текстом был рождён из-за того, что существующие языки для этих новых ниш были слишком неповоротливыми и неоправданно усложнёнными.


                                      1. VolCh
                                        08.09.2017 02:41
                                        -1

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


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


                                        1. divan0 Автор
                                          08.09.2017 02:42

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

                                          Спасибо, это смешно.


                                          1. VolCh
                                            08.09.2017 03:01

                                            А ответ будет? Что пишут на Гоу более эффективно чем на других языках? Сервисы учёта, сервисы документооборота, сервисы моделирования, игровые сервера, ну хоть какой-то пример есть сложных систем, моделирующих реальный человеческий мир? Да, это круто, если Гоу может эффективнее всех взять что-то из базы и отдать по хттп. А примеры когда он создаёт что-то, на основании сотен параметров и событий реального мира и кладёт в базу, есть?


                                            1. divan0 Автор
                                              08.09.2017 03:10

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

                                              Почти все реализации блокчейна пишут на Go, например (btcd, geth, hyperledger, etc). Это конечно, не так круто, как «программы бухучета» из вашего «реального мира», но «проценты там тоже можно начислять» :D


                                              1. VolCh
                                                08.09.2017 09:17
                                                -1

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


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


                              1. SirEdvin
                                06.09.2017 15:33
                                +2

                                Ну и да.


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

                                Вам не стыдно так нагло врать то?) OpenStack вот почти и не слышал про go. Куча бекенда все еще на Java, C#, python и прочих.


                                1. divan0 Автор
                                  06.09.2017 15:36
                                  -1

                                  все еще

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


                                  1. SirEdvin
                                    06.09.2017 15:44

                                    Вам люди пишут про реальные проблемы языка — вы говорите, что это виноваты люди, что они не поняли go-way, что фича X не нужна, что они ничего не понимают.


                                    Что бы слезть с удобных технологий нужна причина. Бенчмарки не решают для большинства проектов, решает инфрастуктура и полезность языка. И тут golang как бы где-то в середине. Те, кто переходят с него на C готовы его целовать, те, кому приходится переходить в более гибких языков на него не из-за проблем с производительностью только плюются и правильно делают. Потому что переход не решит никаких проблем, кроме проблем производительности и то, возможно. Потому что i/o bound задачи такой переход не пофиксит.


                                    1. divan0 Автор
                                      06.09.2017 16:26
                                      -1

                                      вы говорите, что это виноваты люди, что они не поняли go-way

                                      Сами придумали, и сами меня в этом обвинили. Покажите, где я такое говорю.


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

                                      Зачем же переходят, если и языки более гибкие, и производительность не нужна, и инфраструктура и полезность куда лучше, чем Go, и дженерики, и эксепшены — рай же, зачем переходить?


                                      1. SirEdvin
                                        06.09.2017 16:30

                                        Зачем же переходят, если и языки более гибкие, и производительность не нужна, и инфраструктура и полезность куда лучше, чем Go, и дженерики, и эксепшены — рай же, зачем переходить?

                                        Ну так вы же форсите go, вы и отвечайте.


                                        Сами придумали, и сами меня в этом обвинили. Покажите, где я такое говорю.

                                        https://habrahabr.ru/post/337098/?reply_to=10402372#comment_10398648


                                        1. divan0 Автор
                                          06.09.2017 16:33
                                          -1

                                          Ну так вы же форсите go, вы и отвечайте.

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


                                          Сами придумали, и сами меня в этом обвинили. Покажите, где я такое говорю.
                                          https://habrahabr.ru/post/337098/?reply_to=10402372#comment_10398648

                                          И где там слова "люди виноваты" и "go-way". Зачем вы каждый свой комментарий перекручиваете и пишете заведомо ложные вещи, которые порождают опровергающие комментарии, на которые вы отвечаете таким же образом?


                              1. 0xd34df00d
                                06.09.2017 20:45
                                -1

                                И еще раз — если вы настолько свято верите, что без привычных вам дженериков жизни нет и быть не может и это святое и ежедневная необходимость — напишите Experience Report, объясните конкретную проблему, которую вы решали, и как отсутствие дженериков стал вам на пути.

                                Иногда проще, ну, не пользоваться языком.


                                Вы писали experience report'ы о новых стандартах JS?


                                1. divan0 Автор
                                  06.09.2017 21:04
                                  -1

                                  Иногда проще, ну, не пользоваться языком.

                                  Проще, чем что? Чем написать понятным языком о том, как вы решали реальную задачу, и отсутствие пользовательских дженериков привело к тому, что код стал неэффективным, нечитабельным, глючным или некорректным? Да ладно, если бы хотя бы 1% свято верящих в абсолют дженериков понимал вопрос, таких бы репортов было бы уже тысячи, понятно и доступно написанных, без этих надменных бравад о том, какие авторы Go недалекие. Но что-то пока ни один не осилил.


                                  1. 0xd34df00d
                                    06.09.2017 21:13
                                    -1

                                    Одна реальная задача — недоORM на шаблонах, чтобы за меня для простых типов генерил всякие селекты-инсерты.
                                    Другая реальная задача — символьное дифференцирование на этапе компиляции.
                                    Третья реальная задача — некий алгоритм машинного обучения.
                                    Четвёртая реальная задача — матричные операции, где типы шаблонов дают чуть больше гарантий корректности.
                                    Пятая реальная задача — автоматическое вычисление производных через протаскивание через обобщённые алгоритмы дуальных чисел.
                                    Шестая реальная задача — монадка для кодогенерации в самописном компиляторе, которая позволила легко, изящно и безопасно нацеливаться на несколько разных генераторов.


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


                                    1. divan0 Автор
                                      06.09.2017 21:20
                                      -1

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

                                      Генерьте на здоровье. Есть go generate, встроенные библиотеки для работы с AST — такое не сложно написать и генерить себе что хотите для своих типов. Думаю, что если кому-то такое подход нужен был, то уже написано.


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

                                      Я не совсем понимаю о чём речь, но звучит как описание решения какой-то проблемы, а не описание проблемы.


                                      некий алгоритм машинного обучения.

                                      Очень конкретно, да.


                                      4, 5, 6

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


                                      Неужели сложно так описывать проблему, если она реальна?


                                      1. 0xd34df00d
                                        06.09.2017 21:30

                                        Генерьте на здоровье. Есть go generate, встроенные библиотеки для работы с AST — такое не сложно написать и генерить себе что хотите для своих типов.

                                        Ожидал отсылку к go generate, да. Ну, можно замещать темплейты кодогенерацией, в принципе.


                                        Да что там, можно вообще


                                        вот так


                                        1. divan0 Автор
                                          06.09.2017 21:34
                                          -1

                                          Ну, мы же всё-таки решаем проблемы, а не создаём их? :)
                                          У вас в категорию реальных проблем входят только опердени и перекидывающиеся джсонами микросервисы, что ли?

                                          Ну неужели такие вещи нужно объяснять. Это как прийти к водителю Теслы и спрашивать его, куда заливать бензин, вместо того, чтобы объяснить проблему "добраться из пункта А в пункта Б".


                                          1. 0xd34df00d
                                            06.09.2017 21:37
                                            -1

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


                                            Удобно, чо.


                                            1. divan0 Автор
                                              06.09.2017 21:43
                                              -1

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

                                              Вы вправду не видите разницу между "описать проблему" и "описать придуманное решение"? Будь вы продакт менеджером вы прямо так бы и писали в беклог — "сегодня мы должны написать монадку" и все такие — "да, да, пишем монадку, ведь наша бизнес модель построена на решении проблемы отсутствия монадок".


                                              1. SirEdvin
                                                06.09.2017 21:51

                                                Ну нет. Там стоит задача "необходимо заставить разработчиков обрабатывать null-значения и не игнорировать ошибки, а то у нас каждый релиз минимум 10 багов на эту тему". Вот кроме монады Optional ничего для этого не придумали, нужна монада.


                                                Изменять команду или как-то повлиять на индусов в разработке вы не можете.


                                              1. 0xd34df00d
                                                06.09.2017 22:11

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


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


                                                1. divan0 Автор
                                                  06.09.2017 22:43
                                                  -1

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


                                                  1. 0xd34df00d
                                                    06.09.2017 23:41

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

                                                    Строки, действительно, не нужны. Но сравнить производительность и точность на модельных примерах между флоатами и даблами имеет смысл. Или провалидировать на длинной арифметике из boost.multiprecision, скажем. Вот уже и дженерики полезны.


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


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


                                                    Ну и так далее.


                            1. vintage
                              06.09.2017 15:18

                              Да нет там ничего сложного.


                              Парсим шаблон:


                              T sum( T )( T[] list ) {
                                  T result;
                                  foreach( item ; list ) result += item;
                                  return result;
                              }

                              Видим использование:


                              sum!int([ 1 , 2 , 3 ]);

                              Подставляем тип в шаблон, генерируем код и компилируем:


                              int sum( int[] list ) {
                                  int result;
                                  foreach( item ; list ) result += item;
                                  return result;
                              }

                              Видим другое использование:


                              sum!float([ 1.1 , 2.2 , 3.2 ]);

                              Подставляем тип в шаблон, генерируем код и компилируем:


                              float sum( float[] list ) {
                                  float result;
                                  foreach( item ; list ) result += item;
                                  return result;
                              }

                              Уже даже таких простых шаблонов без выведения типов уже хватило бы, но нет, "это слишком сложно".


                              1. divan0 Автор
                                06.09.2017 15:21

                                Да нет там ничего сложного.

                                Это так мило. Ну не умеют люди из Bell Labs и Google парсить шаблоны. Давайте я им ваше резюме скину, научите их?


                                1. vintage
                                  06.09.2017 15:26
                                  +1

                                  Ага, а люди из никому не известной Digital Mars почему-то умеют.


                                  1. divan0 Автор
                                    06.09.2017 15:33

                                    Ага, а люди из никому не известной Digital Mars почему-то умеют.

                                    Что именно они умеют? И почему они неизвестные, если они так много умеют.


                              1. divan0 Автор
                                06.09.2017 15:24

                                Блин, я надеюсь вы пошутили, и не думаете, что дженерики это вот так просто — распарсить шаблон. Иначе совсем печаль.


                                1. vintage
                                  06.09.2017 15:31
                                  +1

                                  Я вам рассказал, как они работают в языке D. А вы так и не рассказали какие же там великие сложности.


                                  1. divan0 Автор
                                    06.09.2017 15:43

                                    1. vintage
                                      06.09.2017 16:01
                                      +1

                                      Я не увидел там никаких сложностей, кроме голословных "это замедлит компиляцию" и "это сгенерирует много одинакового кода" не соответствующих реальности.


                                      1. divan0 Автор
                                        06.09.2017 16:28

                                        Я не увидел там никаких сложностей

                                        Может законтрибьютете в Go, добавите дженериков, если не увидели никаких сложностей? :)


                                        1. vintage
                                          06.09.2017 17:21

                                          Оно мне надо? В D у меня есть и дженерики и исполнение времени компиляции и TLS и куча других прикольных вещей, позволяющих писать мало, а делать много.


                                          1. divan0 Автор
                                            06.09.2017 17:26

                                            А покажите свой гитхаб, хоть посмотрю на те тонны кода, которые вы написали за последние пару лет на D и попытаюсь оценить насколько D прибавил вам продуктивности.

                                            А то мне D не зашел ввиду популярного подхода «сделаем язык с кучей фишек», и остальному миру он как-то тоже не зашел. Не знаю ни одну программу в современном мире софта на D.


                                            1. vintage
                                              06.09.2017 17:41

                                              У меня в профиле всё написано так-то.


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


                                              1. divan0 Автор
                                                06.09.2017 18:27

                                                У меня в профиле всё написано так-то.

                                                Так нет гитхаб профиля.


                                                1. vintage
                                                  06.09.2017 18:33

                                                  Да есть там всё.


                                1. rraderio
                                  06.09.2017 15:34

                                  А что еще?


                              1. SirEdvin
                                06.09.2017 15:27

                                Уже даже таких простых шаблонов без выведения типов уже хватило бы, но нет, "это слишком сложно".

                                Тут проблема в великом и ужастном legacy. Как только вы так сделаете, то потом вам же нужно будет тащить за собой этот не очень продуманный синтаксис веками, как это сейчас делает Java. И это очень грустно для нее, посмотрите только на иерархую классов Property там. Там просто ад из-за того, что примитивы не могут в generic.


                                1. vintage
                                  06.09.2017 15:36

                                  1. SirEdvin
                                    06.09.2017 15:49
                                    +1

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


                                    • Как там решается проблема, когда в шаблон нужно засунуть объект, который должен удовлетворять двум интерфейсам?
                                    • Как обстоит дело с тем, что объект может быть наследником класса любой вложености?
                                    • Как обстоит дело с тем, что объект должен быть предком класса любой вложенности?
                                    • Как обстоит дело с тем, что объект должен быть только нескольких классов и не их предков/наследников?


                                    1. vintage
                                      06.09.2017 17:06
                                      +1

                                      Как там решается проблема, когда в шаблон нужно засунуть объект, который должен удовлетворять двум интерфейсам?

                                      interface A {}
                                      interface B {}
                                      
                                      void foo( T )( T o )
                                      if ( is( T : A ) && is( T : B ) )
                                      {
                                          // ...
                                      }

                                      Как обстоит дело с тем, что объект может быть наследником класса любой вложености?

                                      class A {}
                                      
                                      void foo( T )( T o )
                                      if( is( T : A ) )
                                      {
                                          // ...
                                      }

                                      Или просто:


                                      void foo( A o )
                                      {
                                          // ...
                                      }

                                      Как обстоит дело с тем, что объект должен быть предком класса любой вложенности?

                                      class A {}
                                      class B : A {}
                                      
                                      void foo( T )( T o )
                                      if( is( B : T ) )
                                      {
                                          // ...
                                      }

                                      Как обстоит дело с тем, что объект должен быть только нескольких классов и не их предков/наследников?

                                      class A {}
                                      class B {}
                                      
                                      void foo( T )( T o )
                                      if( is( T == A ) || is( T == B ) )
                                      {
                                          // ...
                                      }

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


                                      1. SirEdvin
                                        06.09.2017 17:14

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


                                        Ну и последний вопрос, который мне очень нравится в java. Может ли подставленный тип влиять на результат выполнения функции?


                                        Это я к тому, что
                                        t -> t*t
                                        и
                                        (DoubleUnaryOperator & Serializable)t -> t*t
                                        внезапно, порождает разные типы одной и той же функции, что довольно удобно в редких случаях.


                                        1. vintage
                                          06.09.2017 17:26

                                          Вот этот кейс я уже не понял. Что это и зачем?


                                          1. SirEdvin
                                            06.09.2017 17:38
                                            -1

                                            Оно работает только через bytecode, а жаль.


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


                                            1. vintage
                                              06.09.2017 17:47

                                              Понятней не стало. Пример бы.


                                              1. SirEdvin
                                                06.09.2017 18:00

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


                                                1. vintage
                                                  06.09.2017 18:17

                                                  Эм, и во что оно сериализуется?


                                                  1. SirEdvin
                                                    06.09.2017 18:19
                                                    -1

                                                    Чисто в информацию о классе. Суть в том, что изменение generic типа, который должна вернуть функция влияет на результат выполнения функции. Оно вряд ли так сильно необходимо, но мне кажется. в рамках D это будет сложно сделать. Или можно будет просто проверок повпихивать и я запутался?)


                                                    1. vintage
                                                      06.09.2017 18:39

                                                      Скорее можно, чем нельзя. Но всё-равно не понятно, что оно там должно выводить и зачем так извращаться.


                              1. Comdiv
                                06.09.2017 16:07

                                sum!float([ 1.1 , 2.2 , 3.2 ]);
                                sum!int([ 1 , 2 , 3 ]);

                                В настоящих задачах нужно учитывать возможность переполнения. В дробях и целых оно учитывается по разному. Учтено ли это в Вашем несложном примере?


                                1. rraderio
                                  06.09.2017 16:21

                                  А как в настоящих задачах вы учитываете переполнение при сложении a + b?


                                  1. Comdiv
                                    06.09.2017 18:40

                                    Зависит от задач, в том-то и дело. Если это целые неотрицательные, то как-то так:

                                    bool sum(int len, int a[len], int *sum, int *i) {
                                      *i = 0;
                                      *sum = 0;
                                      while ((*i < len) 
                                          && (a[*i] >= 0) 
                                          && (*sum <= INT_MAX - a[*i])) 
                                      {
                                         *sum += a[*i];
                                         *i += 1;
                                      }
                                      return *i >= len;
                                    }
                                    

                                    В других случаях это будет по другому.


                                    1. rraderio
                                      07.09.2017 09:10

                                      int a = ???
                                      int b = ???
                                      
                                      int c = a + b

                                      Вы всегда учитываете переполнение при сложении?


                                      1. Comdiv
                                        07.09.2017 14:20

                                        Да, кроме тех случаев, где я об этом забываю.
                                        Есть 2-a сценария:

                                        1. Переполнение невозможно исходя из задачи, потому что известны ограничения на возможные значения. Здесь переполнение, которое может случится только из-за ошибки в алгоритме, должно контролироваться компилятором (gcc -ftrapv, использовать только signed)
                                        2. Переполнение возможно, потому что данные косвенно или прямо получены из источников, где нужные диапазоны значений не гарантируются. В таком случае нужно проверять возможность переполнения и обеспечить их корректную обработку.

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


                                1. vintage
                                  06.09.2017 17:15

                                  1. Comdiv
                                    06.09.2017 18:19

                                    Что, разумеется? Вы написали, что

                                    Да нет там ничего сложного.

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


                                    1. vintage
                                      06.09.2017 18:44
                                      -1

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


                                      1. Comdiv
                                        06.09.2017 19:20

                                        Я не увидел

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


                      1. 0xd34df00d
                        06.09.2017 20:42

                        а эти неучи из Го, пусть даже создавшие Unix, ничего не понимают в жизни

                        Вы, конечно, извините, но с точки зрения дизайна языков я скорее послушаю Бенджамина Пирса какого, чем Роба Пайка. Заговорим о разработке ОС — вот тогда ситуация будет обратной.


                        Иными словами, у вас классическая апелляция к авторитету.


    1. thingInSelf
      05.09.2017 01:03

      Ну все, пойду переписывать все свои Node.js бэки на Go. А если серьезно, как-же достала это выдуманная проблема с языками и платформами (особенное с очень близкими по производительности). Т.е. выбор языка по бенчмаркам куда предпочтительнее, чем скорость разработки функционала / экосистема / синтаксис / высокоуровневость?


      В контексте сравнения именно Go vs Node мы имеем вполне сопоставимые экосистемы.


      1. SuperPaintman
        05.09.2017 02:10

        Я не сравнивал их, а говорил про это.


    1. r-moiseev
      05.09.2017 16:01
      +1

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


      1. divan0 Автор
        05.09.2017 16:12

        Я действительно не могу понять зачем так

        Почитайте статьи тут в хабе Go на эту тему. Если кратко — то Go заставляет относится к ошибкам также уважительно, как и к остальному коду. Часто, к сожалению, после эксепшенов это не так. Ну и еще пачка причин — часть из них тут в комментариях озвучены.


        1. raveclassic
          05.09.2017 19:35
          +1

          Относиться уважительно нужно к данным, а не к обрабатывающему их коду. Если у вас ошибки являются частью данных (привет ADT и Option/Either), то вот тогда вы к ним относитесь уважительно.


          1. divan0 Автор
            06.09.2017 10:40

            А если нет Option/Either, то на ошибки надо забивать? Это где вас так научили?


            1. rraderio
              06.09.2017 10:49

              А если нет Option/Either, то на ошибки надо забивать

              Нет, их надо добавить. Ах, в го не дженериков.


              1. divan0 Автор
                06.09.2017 11:10

                Нет, их надо добавить

                Кому надо?


                1. rraderio
                  06.09.2017 11:12

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


                  1. divan0 Автор
                    06.09.2017 11:20

                    Именно, в Go ошибки это такие же данные, поэтому к ним и относятся уважительно. Вы поняли суть.


                    1. rraderio
                      06.09.2017 11:39

                      Относиться уважительно нужно к данным, а не к обрабатывающему их коду. Если у вас ошибки являются частью данных (привет ADT и Option/Either), то вот тогда вы к ним относитесь уважительно.

                      а не как в go


                      1. divan0 Автор
                        06.09.2017 12:17
                        -1

                        Вы про Go только вчера узнали, и уже составили мнение о том "как в Go" и им пытаетесь кому-то что-то доказывать?
                        Удачи.


                        1. rraderio
                          06.09.2017 12:28

                          Я слежу за go с версии 1.0


                    1. r-moiseev
                      06.09.2017 12:20

                      И именно поэтому я должен по нескольку раз обрабатывать одну и ту же ошибку то там то тут?


                      1. divan0 Автор
                        06.09.2017 15:02
                        -1

                        я должен по нескольку раз обрабатывать одну и ту же ошибку то там то тут?

                        Как вас плющит от одной только мысли, что ошибки нужно обрабатывать :)


            1. raveclassic
              06.09.2017 13:09

              Если нет Option/Either (или хотя бы инструмента для их реализации), мне не нужен такой язык, увы.


              1. SirEdvin
                06.09.2017 13:39
                -1

                Он есть. Это делается например, вот тут. Но из-за отсутствия дженериков вы вынуждены будете делать приведение интерфейса к нужному значению :) И так каждый раз.


                1. raveclassic
                  06.09.2017 17:39

                  Я правильно понимаю, что interface{} — это, своего рода, any? То есть каждый раз кастовать к any? Потрясающе :)


                  1. SirEdvin
                    06.09.2017 17:41

                    К сожалению, я не знаю, какой язык вы имеете ввиду. Мне ближе всего в этом вопросе Java и в такой терминологии interface{} — это Object, к которому можно привести любой объект.


                    1. raveclassic
                      06.09.2017 19:35

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


                  1. divan0 Автор
                    06.09.2017 18:32
                    -1

                    То есть каждый раз кастовать к any? Потрясающе :)

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


                    Вы хотите понять, как в Go решают задачи или хотите доказать себе, что Go плохо продуман? Если первое, то можете спрашивать, постараюсь объяснить. Если второе, то это вам к SirEdvin.


                    1. SirEdvin
                      06.09.2017 18:37
                      -2

                      Docker разрабатывают новички, так и запишем. Ну и да, вы только подтверждаете вот этот комментарий.


                    1. raveclassic
                      06.09.2017 19:17
                      +1

                      Окей, объясните мне, как реализовать Option с сохранением типов аргумента и результата. Например, для Option<Number> нужна реализация map :: Option<Number> ~> (Number -> B) -> Option<B>. Типичный представитель библиотечного кода. Как решаются такие вещи, или они не решаются вовсе?


                      1. divan0 Автор
                        06.09.2017 19:34
                        -1

                        Вы сейчас пытаетесь решение какой-то проблемы из одного языка воплотить в другом языке. Ну тоесть это как если я спрошу «Окей, объясните мне, как в Rust инициировать запуск внеплановый сборщик мусора» или «Окей, как в Haskell запустить горутину».

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


                        1. raveclassic
                          06.09.2017 19:44
                          +1

                          100% ожидаемый ответ, конечно, ну да ладно.


                          Вот вам задачка — пишите вы библиотечку для тех же бинарных деревьев. Ну и, понятное дело, хотите иметь полиморфные функции для работы с этим деревом, не копипастить же их. Далеко ходить не надо, берем нашу подругу map, принимающую аргументом лямбду A -> B. Но, так как вы пишете библиотечный код, нужно как-то ограничить тип аргумента это лямбды. Если дерево интов — значит в аргументе инт, если строк — строка.


                          1. divan0 Автор
                            06.09.2017 20:17
                            -1

                            100% ожидаемый ответ, конечно, ну да ладно.

                            Это не да ладно, это в корне меняет всю суть дискуссии.


                            пишите вы библиотечку для тех же бинарных деревьев.

                            Стоп, нет, ещё раньше. Вот приходите вы на работу, выпили кофе, стендап, все дела и что, у вас прямо так в проекте задача и стоит — "Написать библиотечку для тех же бинарных деревьев"? Давайте шаг назад, что привело вас к тому, что вы хотите написать "библиотечку для тех же бинарных деревьев".


                            А то пока что это 100% предсказуемый студенческий ответ, для которых задачи, стоящие перед программистами тождественны "написать полиморфный тип данных на таком-то языке с такими-то фичами". Мы же говорим о реальном мире, так что рассказывайте, как оно у вас происходит.


                            1. raveclassic
                              06.09.2017 20:24
                              +1

                              Еще более ожидаемый ответ.


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


                              Я вам привожу наиклассический пример — деревья. Деревья чисел, деревья строк, деревья котов, чего угодно. Так и происходит. Или вы не признаете классические структуры данных и алгоритмы для них, так как в го вы их не используете?


                              EDIT:


                              у вас прямо так в проекте задача и стоит

                              И такое бывает, так как большую часть времени я пишу именно библиотечный код "под все" и не могу позволить иметь 500 функций mapNumber, mapString, mapCat.


                              1. divan0 Автор
                                06.09.2017 20:56
                                -1

                                Вы понимаете, что вы тут как бы пытаетесь намекнуть

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


                                вы не признаете классические структуры данных

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


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


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


                                За "поведение" в Go четко отвечает один ортогональный концепт — это interface. Вы определяете интерфейс для нашего типа, назовем его Node:


                                type Node interface {
                                    Less(than Node) bool
                                }

                                Этот интерфейс содержит лишь один метод, и любой тип, к которому мы добавим метод Less(Node) bool автоматически будет удовлетворять этому интерфейсу.


                                Дальше вы реализуете сам алгоритм, где вы уже при проходе используете метод Less(), даже не зная, что там под капотом. Алгоритму и не нужно знать — он работает с поведением типа.


                                Из очевидных минусов в том, что в функции Less придется приводить интерфейс к конкретному типу, что равно примерно порядка десяткам наносекунд:


                                type Int int
                                
                                func (a Int) Less(b Node) bool {
                                    return a < b.(Int)
                                }

                                Теперь библиотечку вашу вы используете так:


                                import "github.com/myuser/btree"
                                
                                ...
                                
                                tree := btree.New()
                                ..
                                tree.Insert(Int(3))
                                tree.Insert(Int(4))
                                tree.Has(Int(3))

                                и т.д.


                                Ваша очередь отвечать на вопрос.


                                1. 0xd34df00d
                                  06.09.2017 21:06
                                  +1

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


                                  1. divan0 Автор
                                    06.09.2017 21:14
                                    -1

                                    Именно, интерфейс определяет пакет (библиотека), которая будет консьюмером этого интерфейса. А кто его уже реализовывает, делает это под этот контекст, да.


                                    А можно как-то единожды описать операцию сравнения для типа, а потом использовать её хоть в дереве, хоть в бинарном поиске, хоть в сортировке?

                                    Конечно, так и должно быть в идеале. Это же неявное удовлетворение интерфейса (нету никакихimplements Node).


                                    1. 0xd34df00d
                                      06.09.2017 21:15
                                      +1

                                      Тогда кто пишет этот код?


                                      func (a Int) Less(b Node) bool {
                                          return a < b.(Int)
                                      }


                                      1. divan0 Автор
                                        06.09.2017 21:22
                                        -1

                                        Тогда кто пишет этот код?

                                        Пользователь библиотеки и owner типа, который он хочет использовать с этой библиотекой.


                                        1. 0xd34df00d
                                          06.09.2017 21:31

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


                                          1. divan0 Автор
                                            06.09.2017 21:36
                                            -1

                                            мне необходимо отдельно явно написать код, который упоминает вашу библиотеку?

                                            Конкретно в этом случае — да, придется. Есть другой подход, для массивов, например — Less(i, j int) bool, тут ничего импортировать не придется.


                                            1. 0xd34df00d
                                              06.09.2017 22:28

                                              Какой трындец Спасибо, ясно.


                                1. SirEdvin
                                  06.09.2017 21:18
                                  -2

                                  Ну да. Ведь код вида tree.Insert(Int(3)), которым будет покрыто все ваше приложение нужно оценивать с точки зрения именно производительности, а не с точки зрения "АААААААА, как на этом вообще можно писать".


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


                                  1. divan0 Автор
                                    06.09.2017 21:23
                                    -1

                                    SirEdvin вы, как всегда, не в тему. Вы не знали, для чего нужны бинарные деревья? И рассказали историю про то как вы не смогли найти библиотеку для бинарных деревьев, не смогли 2Гига засунуть в память и не смогли написать бинарное дерево сами? Ок, аплодисменты.


                                    1. SirEdvin
                                      06.09.2017 21:25

                                      divan0 вы, как всегда, не умеете читать. Пропустили кусок текста о специфических требованиях к представлению бинарных деревьев, с чего-то взяли, что не смогли написать бинарное дерево сами. Конечно, смогли, мы же не взяли Go.


                                1. raveclassic
                                  06.09.2017 23:43

                                  Я пытаюсь услышать реальную задачу, серьезно.

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


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

                                  Поздравляю, вы вывели Setoid+Ord. И да, реализуете вашим типом equals и lte и вперед.


                                  Дальше вы реализуете сам алгоритм, где вы уже при проходе используете метод Less(), даже не зная, что там под капотом. Алгоритму и не нужно знать — он работает с поведением типа.

                                  Здорово, только мне нужна map для этих деревьев (а не для типа, так что реализация функтора типом не катит) с ограничением типа аргумента лямбды. Мне нужно деревья строк приводить к деревьях интов (дерево одной команды переиспользовать в другой) с последующим траверсом в Option. С сохранением внутреннего типа значений ноды.
                                  Go?


                                  Из очевидных минусов в том, что в функции Less придется приводить интерфейс к конкретному типу, что равно примерно порядка десяткам наносекунд:

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


                                  tree.Insert(Int(3))
                                  tree.Insert(Int(4))
                                  А если потом вот так?
                                  tree.Insert(String('123')) //синтаксис может быть неточным

                                  PS. Мне, в принципе, уже хватило, чтобы понять, как в го строится разработка — от минимальной задачи, а не от абстракции. Потому-что абстракций толком не построить, инструменты хилые для этого. Да, с какой-то стороны это может быть удобным, ну, мол, да че там касты между деревьями, я ж не буду это каждый день делать. А если тикет прилетит — ну уговорю менеджера не делать, типа мы работаем на 10нс быстрее всего остального, так что деревья скопипастим. Так?


                                  1. 0xd34df00d
                                    06.09.2017 23:56

                                    Здорово, только мне нужна map для этих деревьев (а не для типа, так что реализация функтора типом не катит) с ограничением типа аргумента лямбды.

                                    А это, кстати, плохая идея для деревьев-множеств, потому что map (const ()) свернёт всё дерево в один узел и не сохранит вам форму, что не очень приятно по ряду причин.


                                    1. raveclassic
                                      07.09.2017 00:02
                                      +1

                                      Дельное замечание. (EDIT: и тут включается ССЗБ, на самом деле)
                                      Но поставленного вопроса оно все-равно не решает.


                                  1. divan0 Автор
                                    07.09.2017 02:17
                                    -1

                                    Дано: три команды, которым нужны бинарные деревья

                                    Давайте еще попытку. В чем задача состояла? Вам продакт менеджер так и сказал — "нужно написать три команды, которым нужны бинарные деревья"? Компания называется "бинарные деревья для команд"? :) В чем такая сложность описать задачу, которую вы решали?


                                    1. raveclassic
                                      07.09.2017 02:34

                                      А вы забавный :) как вы лихо увиливаете от задачи


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


                                      Но я могу и что-нибудь попроще описать, чего ходить вокруг да около, возьмем ваш же пример:


                                      tree := btree.New()
                                      tree.Insert(Int(3))
                                      tree2 := btree.New()
                                      tree2.Insert('abc')

                                      Запретите в tree пихать строки, а в tree2 инты. Это обычное требование к статически типизированному библиотечному коду.


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


                                      1. divan0 Автор
                                        07.09.2017 05:25
                                        -2

                                        как вы лихо увиливаете от задачи

                                        Сказал человек, который пол дня не может ответить, какую задачу он решает.


                                        и это фееричный факап для типизированного языка

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


                                        1. raveclassic
                                          07.09.2017 12:06

                                          Ну вы и троль! :D
                                          Вот задача. Вы: "Это не задача!". Вам: "Ок, вот еще одна". Вы: "Не, не вижу!". А потом выстреливает такое закономерное "ой все".


                                          Просто потрясающе! Жаль вашего работодателя, вы небось с каждым тикетом бегаете к PMO/архитекторам с допросами "Что вы тут напридумывали? Какую вы тут задачу вообще решаете?". Ну просто 10 из 10.


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


                                          1. divan0 Автор
                                            07.09.2017 12:35
                                            -1

                                            Вот смотрите — вы захотели написать что-то такое, что, по вашему, заденет собеседника — постарались и написали. В чём проблема также постараться и ответить на вопрос — «какую проблему вы решали?» :)

                                            Я люблю этот вопрос в дискуссиях про дженерики, потому что на него практически никогда не может ответить — все начинают описывать решение, которое у них есть в голове, а не саму проблему, увиливать от ответа и всячески уходить от темы. Это как раз показывает большую пропасть между теми, кто языки программирования любит как «вещь в себе» — за фишечки и навороты, а кто колбасит код по 6 часов в день ежедневно и решает реальные проблемы.

                                            Жаль, я думал вы будете первый, кто внятно даст ответ на такой простой вопрос.


                                            1. raveclassic
                                              07.09.2017 13:08
                                              +1

                                              Вот смотрите — вы захотели написать что-то такое, что, по вашему, заденет собеседника — постарались и написали. В чём проблема также постараться и ответить на вопрос — «какую проблему вы решали?» :)

                                              Я вам талдычу который раз уже. Вас устраивает только формат "Бизнесу нужно срубить с продажи приложения в 2 раза больше денег в этом квартале"? Если go не решает простые задачи, прилетающие после нескольких словев декомпозиции, то так и говорите, что не решает, а не то, что постановка неверная. Иначе мы ходим по кругу.


                                              Это как раз показывает большую пропасть между теми, кто языки программирования любит как «вещь в себе» — за фишечки и навороты, а кто колбасит код по 6 часов в день ежедневно и решает реальные проблемы.

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


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


                                              1. divan0 Автор
                                                07.09.2017 13:15
                                                -1

                                                Я вам талдычу который раз уже.

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


                                                решит задачу с деревьми за пару минут, но не на Go

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


                                            1. rraderio
                                              07.09.2017 14:16
                                              +2

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

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

                                              Ок, в go есть горутины, скажите какую проблему решают горутины?


                                              1. divan0 Автор
                                                07.09.2017 17:01
                                                -1

                                                не решают проблемы, они помогаю в разработке решения.

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


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


                                                Но сначала нужно объяснить проблему, а вы не можете.


                                                go есть горутины, скажите какую проблему решают горутины?

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


                                                1. SirEdvin
                                                  07.09.2017 17:05
                                                  -1

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

                                                  То есть "написать бинарное дерево" не бизнес-задача "а написать приложение, которое эффективно использует все ядра процессора" — это бизнес-задача? Ясно-понятно.


                                                  1. divan0 Автор
                                                    07.09.2017 17:05
                                                    -1

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


                                                    1. SirEdvin
                                                      07.09.2017 17:09

                                                      Ну то есть у вас в беклоге бизнес-аналитики так и пишут "написать приложение, которые эффективно использует все ядра процессора"?


                                                      Мне интересно, вы серьезно не замечаете проблемы с вашей логикой?)


                                                      1. divan0 Автор
                                                        07.09.2017 17:11
                                                        -1

                                                        Мне интересно, вы серьезно не замечаете проблемы с вашей логикой?)

                                                        Я вам не мешаю сам с собой разговаривать?


                                                    1. raveclassic
                                                      07.09.2017 17:19
                                                      +1

                                                      А вы не передергивайте.


                                                      То есть "написать бинарное дерево" не бизнес-задача "а написать приложение, которое эффективно использует все ядра процессора" — это бизнес-задача?

                                                      Это прекрасный пример вашей логики.


                                                      какую задачу вы решали

                                                      Поставленную. Точка. Что тут непонятного? Вы не выполняете поставленные задачи? Или вы сам себе режиссер? В таком случае нам, наверное, нечего обсуждать, я наемный рабочий и, как это вы говорите, "колбашу 6 часов и решаю реальные задачи". Вместо распыления и поиска пути, как мне это задачу не решать.


                                                      1. divan0 Автор
                                                        07.09.2017 17:28

                                                        > Поставленную. Точка. Что тут непонятного? Вы не выполняете поставленные задачи?

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


                                                        1. raveclassic
                                                          07.09.2017 18:08
                                                          +1

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


                                                          1. divan0 Автор
                                                            07.09.2017 18:11

                                                            И пусть же нам всем повезет, и все мы не будем иметь дело

                                                            Ээ, подождите стихи писать, мы тут про дженерики обсуждали. Если я не ошибаюсь, вы писали сначала, что вам нужно написать "библиотечку для бинарных деревьев", потом написали что у вас задача стояла "написать три команды, которым нужны бинарные деревья", а теперь оказывается, что вы писали банальную апишечку, которая сохраняет три похожих сущности в базу, верно?


                                                            Бинарное дерево где тут и в каком моменте вам пришлось писать библиотечку для бинарных деревьев для этой задачи?


                                                            1. raveclassic
                                                              07.09.2017 18:18

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


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


                                                              1. divan0 Автор
                                                                07.09.2017 18:21

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

                                                                Аа, команды всмысле teams? Мне прямо уже вас страшно спрашивать, но зачем вам для апишечки, которая пишет в базу 3 сущности, писать бинарное дерево для разных команд(!)? Тоесть я снова спрашиваю, какую проблему вы решали этим? Как-то не сходится пока что, не могли бы вы детальней объяснить?


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

                                                                А на чём писали, кстати, что не было готовой библиотеки для binary tree?


                                                                1. raveclassic
                                                                  07.09.2017 18:26
                                                                  +1

                                                                  но зачем вам для апишечки, которая пишет в базу 3 сущности,

                                                                  Ау! Мне на надо их писать в базу, при чем тут база вообще? Вы не умеете мыслить абстрактно и все задачи сводите к записи в базу?


                                                                  А на чём писали, кстати, что не было готовой библиотеки для binary tree?

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


                                                                  1. divan0 Автор
                                                                    07.09.2017 18:52

                                                                    Ау! Мне на надо их писать в базу, при чем тут база вообще?
                                                                    Нам надо сделать API для добавления продуктов,

                                                                    А куда вы их добавляете? В блокчейн? Ну ладно, придираюсь, согласен, хотя хотелось бы понимать задачу полнее. Потому что до сих пор не ясно, как связано "API для добавления продуктов" и "бинарные деревья для трех разных групп разработчиков".


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

                                                                    Я имел ввиду на чём писали своё решение. То, что вам не нужно было писать бинарное дерево это с самого начала было понятно.


                                                                    Но мы же go тут обсуждаем, где их нет.

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


                                                                    1. raveclassic
                                                                      07.09.2017 19:03
                                                                      +1

                                                                      как связано "API для добавления продуктов" и "бинарные деревья для трех разных групп разработчиков"

                                                                      Это разные люди пишут.


                                                                      Я имел ввиду на чём писали своё решение. То, что вам не нужно было писать бинарное дерево это с самого начала было понятно.

                                                                      А какая разница? На языке с дженериками. Ну, раз интересно, на TS.


                                                                      описанная вами задача решается без дженериков

                                                                      Покажите же наконец!


                                                                      и на интерфейсах

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


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

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


                                                                      1. divan0 Автор
                                                                        07.09.2017 19:25
                                                                        -1

                                                                        Это разные люди пишут.

                                                                        И что из этого следует? Вам нужно API для добавления продукта куда-то. В каком месте возникает бинарное дерево?


                                                                        Ну, раз интересно, на TS.

                                                                        О, господи. На ангуляре 4 ещё небось? Что ж вы раньше не сказали, я бы с пониманием относился. Это проясняет ваши взгляды на разработку софта.


                                                                        Покажите же наконец!

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


                                                                        И как же интерфейсы без дженериков мне реализуют map для дерева с сохранением типа аргумента лямбды?

                                                                        Вы же апишечку пишете на TS, откуда у вас появляются фантазии писать "map для дерева с сохранением типа аргумента лямбды". Мне кажется вы решаете больше проблемы, которые сами себе придумываете теми инструментами, которые выбираете (TS, ха-ха), вместо того, чтобы решать конкретные задачи. Это популярная тема среди JS-мира, увы :(


                                                                        увольте.

                                                                        Я бы вас даже не взял, без обид. Впрочем, со временем вы всё равно начнете ценить прагматичность и практичность, поработаете в разных командах, начнете ненавидеть сложность, особенно придуманную и привнесённую, и ценить практичность и элегантную простоту, научитесь отличать лютое Г от красивых решений. Ах да, ещё когда научитесь доступно изъясняться и рассказывать проблему. Без ясной коммуникации никак. Вот тогда может и уволю :)


                                                                        1. raveclassic
                                                                          07.09.2017 19:33
                                                                          +2

                                                                          Вам нужно API для добавления продукта куда-то. В каком месте возникает бинарное дерево?

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


                                                                          О, господи. На ангуляре 4 ещё небось? Что ж вы раньше не сказали, я бы с пониманием относился. Это проясняет ваши взгляды на разработку софта.

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


                                                                          Вам же уже два примера кода написали. Вы хотите, чтобы вам лично веки приподняли, или как ещё показать?
                                                                          Вы же апишечку пишете на TS, откуда у вас появляются фантазии писать "map для дерева с сохранением типа аргумента лямбды". Мне кажется вы решаете больше проблемы, которые сами себе придумываете теми инструментами, которые выбираете (TS, ха-ха), вместо того, чтобы решать конкретные задачи. Это популярная тема среди JS-мира, увы :(
                                                                          Я бы вас даже не взял, без обид. Впрочем, со временем вы всё равно начнете ценить прагматичность и практичность, поработаете в разных командах, начнете ненавидеть сложность, особенно придуманную и привнесённую, и ценить практичность и элегантную простоту, научитесь отличать лютое Г от красивых решений. Ах да, ещё когда научитесь доступно изъясняться и рассказывать проблему. Без ясной коммуникации никак. Вот тогда может и уволю :)

                                                                          Браво! Это просто победа! Сохраню ссылку в копилку.


                                                                          PS. Боже упаси кого-то взять вас в штат.


                                                                          1. divan0 Автор
                                                                            07.09.2017 19:41

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

                                                                            Вы же чуть раньше писали, что вам нужно было API для добавления разных продуктов? Уже отказываетесь от своих же объяснений?


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

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


                                                                            PS. Боже упаси кого-то взять вас в штат.

                                                                            Я могу ещё доплатить, чтобы вы не брали людей в штат. Пожалейте людей.


                                                                            1. raveclassic
                                                                              07.09.2017 20:35

                                                                              Вы же чуть раньше писали, что вам нужно было API для добавления разных продуктов? Уже отказываетесь от своих же объяснений?

                                                                              Сектор пруф на барабане!


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

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


                                                                              1. divan0 Автор
                                                                                07.09.2017 20:48

                                                                                Сектор пруф на барабане!
                                                                                https://habrahabr.ru/post/337098/#comment_10405048

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


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


                                                                                1. raveclassic
                                                                                  07.09.2017 23:46

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


                                                                                  1. 0xd34df00d
                                                                                    07.09.2017 23:49
                                                                                    -1

                                                                                    В этой задаче не демонстрируются преимущества Go, а значит, она не нужна.


                                                                                  1. divan0 Автор
                                                                                    08.09.2017 00:09

                                                                                    ну что не понятно в задаче?

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


                                                                                    Так понятней?


                                                                                    1. raveclassic
                                                                                      08.09.2017 00:16

                                                                                      Вон вам выше ответили уже.


                                                                                      Давайте сфокусируемся, что мы тут обсуждаем? Вы меня пытаетесь поймать или мы все же пытаемся решить задачу с деревьями на go? Если первое, то ловите на здоровье, но диалога не будет (как собственно его и сейчас нет), если второе — расскажите, как вы будете имитировать полиморфизм. Мне действительно интересно, как это делается. Ну а если не делается, прекратите уже паясничать и ответьте прямо "нет, такие задачи на го не решаются, он хорош в других областях".


                                                                                      1. divan0 Автор
                                                                                        08.09.2017 00:33

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


                                                                                        Формулировать задачу "как вы делаете сохранение типа аргумента лямбды" некорректно, потому что а если в каком-то языке нет лямбды — то что вы вообще спрашиваете? Я приводил пример выше — это как спрашивать "как вы в Хаскелле запускаете горутины". Ну, согласитесь, это некорректно.


                                                                                        Более того, мы же не сферического коня в вакууме обсуждаем, а программирование. Люди не программируют просто так — они решают задачи и проблемы, пишут софт для чего-то. Нет такого бизнеса "компания по написанию монад" или "корпорация написания полиморфических лямбд".


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


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


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


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


                                                                                        1. raveclassic
                                                                                          08.09.2017 00:37
                                                                                          +1

                                                                                          "нет, такие задачи на го не решаются, он хорош в других областях"

                                                                                          Ну, то есть, никак не решаются?
                                                                                          Я вас вторые сутки к этому подвожу.


                                                                                          EDIT: вам что, стыдно за го, что на нем нельзя писать полиморфные деревья? странно, вы же вроде за другие преимущества топите… получается, что стыдно?


                                                                                          1. divan0 Автор
                                                                                            08.09.2017 00:53
                                                                                            -1

                                                                                            Ну, то есть, никак не решаются?
                                                                                            Я вас вторые сутки к этому подвожу.

                                                                                            Я правильно вас понял?


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

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


                                                                                            1. raveclassic
                                                                                              08.09.2017 01:09

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


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


                                                                                              1. divan0 Автор
                                                                                                08.09.2017 01:13

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


                                                                                                1. raveclassic
                                                                                                  08.09.2017 01:20

                                                                                                  Это наш "диалог". Или у вас в голове и такое не укладывается? Ой все?


                                                                                                  Или все-таки они не решаются?


                                                                                        1. 0xd34df00d
                                                                                          08.09.2017 00:38

                                                                                          Я приводил пример выше — это как спрашивать «как вы в Хаскелле запускаете горутины».

                                                                                          Естественно, потому что горутины — это кусок Go. Но чем forkIO, async и прочие упомянутые в комментарии, который получил минус вместо ответа, существенно отличаются от горутин?


                                                                                          Вас и про Go никто не спрашивает, как в Go сделать частичную специализацию С++-шаблонов, или как в Go автоматически вывести реализацию тайпкласса компилятором. Чувствуете разницу с вопросами, которые вам задают?


                                                                                          1. divan0 Автор
                                                                                            08.09.2017 00:55

                                                                                            Вас и про Go никто не спрашивает, как в Go сделать частичную специализацию С++-шаблонов,

                                                                                            Спрашивают. И рассказывают друг-другу какой Go убогий, потому что там нет С++ шаблонов. Чувствуете уровень?


                                                                                            1. 0xd34df00d
                                                                                              08.09.2017 01:00

                                                                                              Нет, там спрашивают вообще про хоть какие-то возможности к обобщённому программированию. Можно, конечно, сказать, что go generate нас всех спасет, но это, как, ну, не знаю.


                                                                                              1. divan0 Автор
                                                                                                08.09.2017 01:07

                                                                                                Нет, там спрашивают вообще про хоть какие-то возможности к обобщённому программированию.

                                                                                                Как бы вам не хотелось смягчить градус неадеквата некоторых комментаторов, но нет. Уже было неоднократно рассказано и про встроенные generic-типы, и про решения многих задач интерфейсами, и развенчан миф, про то, что дженерики нужны на каждом шагу, и показан пример как то, что человек хотел делать дженериками, делается банальными интерфесными типами, и про go generate тоже упомянуто. Этого было достаточно, чтобы ищущий ответ человек, действительно решил углубиться в тему. Но этого всего тут я не вижу, пока только неудачные попытки самих себя убедить, что они умные, а авторы Go идиоты.


                                                                                                1. raveclassic
                                                                                                  08.09.2017 01:11
                                                                                                  -1

                                                                                                  аууу, вон ниже вы даже ветку про DI замолчали, потому-что адекватный DI невозможнен
                                                                                                  про map я уже выше написал, вы решили половину задачу, решаемую половину


                                                                                                1. 0xd34df00d
                                                                                                  08.09.2017 01:12

                                                                                                  и про решения многих задач интерфейсами

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


                                                                                                  Ну, для микросервиса сойдёт, в принципе.


                                                                        1. 0xd34df00d
                                                                          07.09.2017 19:53

                                                                          О, господи. На ангуляре 4 ещё небось? Что ж вы раньше не сказали, я бы с пониманием относился. Это проясняет ваши взгляды на разработку софта.

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


                                                                          1. divan0 Автор
                                                                            07.09.2017 19:59

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

                                                                            Дельно, а почему вам это пришло в голову только после подколок ангуляра, а десятки подколок от js-школоты про Go вы спокойно приняли? :)


                                                                            А то, знаете, мне тоже много чего есть сказать про Go и про проекты, которые на нём типично пишут.

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


                                                                            1. 0xd34df00d
                                                                              07.09.2017 20:06

                                                                              Дельно, а почему вам это пришло в голову только после подколок ангуляра, а десятки подколок от js-школоты про Go вы спокойно приняли? :)

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


                                                                              Впрочем, судя по тому, что у меня за ночь в почте накопилось, чуть ниже мне таки придётся не удержаться и тоже подколоть :(


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

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


                                                                              1. divan0 Автор
                                                                                07.09.2017 20:43

                                                                                а не людей, разрабатывающих на этих языках, и их подходы.

                                                                                Вы либо не всё прочитали, либо просто biased слишком. :) В одном из первых комментариев даже с воинствующими мусульманами сравнивали сразу всех, кто пишет на Go и дальше по стандартному списку.


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

                                                                                Смешной пример — знаете, сколько братьям Райт пришлось наслушаться про "законы физики", и про то как всем остальным очевидно, что машина тяжелее воздуха ну никак не может летать.


                                                                                В целом, я всегда прислушиваюсь ко мнению тех, кто имел равнозначный опыт и с А и Б, и может сравнить. Те, кто работал только с А, и с позиции А поливает грязью Б, всегда неправы и олицетворяют образец невежества. Я с таким, правда, в основном только на Хабре сталкиваюсь, не знаю почему.


                                                                                1. 0xd34df00d
                                                                                  07.09.2017 21:04

                                                                                  Вы либо не всё прочитали, либо просто biased слишком. :)

                                                                                  Раньше поток комментариев был больше :)


                                                                                  Смешной пример — знаете, сколько братьям Райт пришлось наслушаться про «законы физики», и про то как всем остальным очевидно, что машина тяжелее воздуха ну никак не может летать.

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


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


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


                                                                                  Но Go не настолько выдающийся, чтобы на нём надо было прям писать.


                                                                                  1. divan0 Автор
                                                                                    07.09.2017 21:50

                                                                                    Ну это какие-то совсем идиоты были, достаточно было посмотреть на небо и на птиц.

                                                                                    Ну вот вы сами и ответили.


                                                                                    Но Go не настолько выдающийся, чтобы на нём надо было прям писать.

                                                                                    Писать надо на том, что более продуктивно и приятно. Лично я пока не вижу Go альтернатив в той нише, для которой он создан. Он тут сильно (в хорошем смысле) отличается от мейнстрима, в котором гонятся за выдающимися фишечками, и варятся в собственной accidental complexity как говорит Брукс. И меня радует, что всё больше и больше людей это понимают.


                                                                                    1. 0xd34df00d
                                                                                      07.09.2017 22:46

                                                                                      Ну вот вы сами и ответили.

                                                                                      На то, что границы применимости аналогий не бесконечны, да.


                                                                                      Писать надо на том, что более продуктивно и приятно. Лично я пока не вижу Go альтернатив в той нише, для которой он создан.

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


                                                                                      1. divan0 Автор
                                                                                        07.09.2017 23:03

                                                                                        А какая ниша-то?

                                                                                        Просто сделайте апгрейд с hardware на cloud, и замените C на Go. Примерно такая. В основном, это конечно же, любой серверный софт (есть очень мало кейсов, где есть смысл писать сервер нынче не на Go) во всем его разнообразии, утилиты, мобильные приложения, базы данных, блокчейн реализации, всевозможные молотилки данных и вычислений (вплоть до псевдо реал тайм) и в таком духе. Ваши набросы про "не сильно сложной предметной логикой" и вот это всё не очень в тему.


                                                                                        1. 0xd34df00d
                                                                                          07.09.2017 23:44

                                                                                          есть очень мало кейсов, где есть смысл писать сервер нынче не на Go

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


                                                                                          А для всего остального — какие возможности для этого Go предоставляет?


                                                                                          всевозможные молотилки данных и вычислений (вплоть до псевдо реал тайм)

                                                                                          Зачем там го, непонятно, если там уже неплохо себя чувствуют плюсы с местами фортраном, ну и питон как клей для всяких numpy.


                                                                                          1. divan0 Автор
                                                                                            08.09.2017 00:22

                                                                                            Ну, я боюсь, что у вас, что у меня тут весьма нерепрезентативная выборка.

                                                                                            Ну вот смотрите, реальный кейс. Недавно проходил конкурс https://highloadcup.ru, который тут был анонсирован на Хабре. Там очки давались за корректность и за суммарную скорость ответа, если грубо. Был месяц. Понятное дело, что в таких условиях есть смысл тюнить и писать велосипеды, но не суть. Вот распределение языков:


                                                                                            image


                                                                                            C++ решения тут на первом месте по количество, но на втором Go. По рейтингу, в первой десятке.- C/C++, одно на Go, и дальше Go во второй десятке.


                                                                                            Но интересно было другое. В начале конкурса решение на Go было в топе пару недель — человек написал его за пару дней, потратив на порядок меньше телодвижений, чем другие, пишущие на других "объективно хороших" языках. Go поначалу хорошо там лидерство держало, и даже я потратил пол воскресенья на то, чтобы с нуля прочесть задачу и реализовать решение, и даже без танцев с бубном был на 9 месте. Ещё раз — пол воскресенья.


                                                                                            Народ же на С++/Rust/Java и прочих "правильных языках" дописали свои решения уже ближе к третьей неделе конкурса, заоптимизировали и, понятное дело, свои миллисекунды выиграли. Java программистов в топ50 прошли только 3, как видно из графика, хотя их, как раз было большинство. Ноды, пхп и прочего мусора, там, естественно нет в топ50.


                                                                                            Вобщем, если вам нужно выжимать микросекунды, есть время на то чтобы долго и вдумчиво писать и оптимизировать всё — C++ хороший выбор, high-frequency trading ниша например очень ок. Но среднестатические сервера, где нет реалтайма, где 200 микросекунд погоды не сделают, где всё давно бежит в kubernetes — ваши потраченные недели на чуть более производительный, но нечитабельный и потенциально безопасный код на C++, который компилируется пол часа (против 2 секунд в Go) и сложно поддающийся рефакторингу — того не стоит. Поэтому для 90% современного серверного софта лучшего варианта, чем Go я не вижу. Хаскель — язык, на который надо потратить 4 года, чтобы хоть что-то не стыдное написать — это, понятное дело, глупость и практический опыт применения Хаскелля уже должен был дать понять, что время входа это таки фактор.


                                                                                            1. 0xd34df00d
                                                                                              08.09.2017 00:29
                                                                                              +1

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

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


                                                                                              Ещё раз — пол воскресенья.

                                                                                              Эх, жаль, я упустил.


                                                                                              Вобщем, если вам нужно выжимать микросекунды, есть время на то чтобы долго и вдумчиво писать и оптимизировать всё — C++ хороший выбор, high-frequency trading ниша например очень ок.

                                                                                              Ну, я не в HFT, но производительность, что throughput, что latency, весьма важна.


                                                                                              Хаскель — язык, на который надо потратить 4 года, чтобы хоть что-то не стыдное написать

                                                                                              4 года — это как-то совсем перебор. 4 месяца — возможно, но не года уж точно. А на каком-нибудь там snap тудушечку состряпать тоже не сильно долго без начального знания хаскеля. Хотя, возможно, это мой bias как уже давно знающего человека.


                                                                                              и практический опыт применения Хаскелля уже должен был дать понять, что время входа это таки фактор.

                                                                                              Конкретно мне это не сильно мешает писать на хаскеле вполне себе полезный и используемый код.


                                                                                              1. divan0 Автор
                                                                                                08.09.2017 00:47

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

                                                                                                Писать можно было на чём угодно, и на питоне тоже писали. Питон на порядок, если не два медленнее Go, не понятно, с чего вы ожидаете что питон бы был в топе. По скорости написания Go как раз сравним с Питоном. Вообще, у меня первые субъективные ощущения были в Go, что он чувствуется как динамический скриптовый язык, хотя на самом деле статически типизированный и быстрый (вероятно потому что я много поначалу баловалс с go run, или прямо из vim-а запуская), и из-за субсекундной компиляции это даже не чувствовалось, что там вообще этот этап есть.


                                                                                                Ну, я не в HFT, но производительность, что throughput, что latency, весьма важна.

                                                                                                Без обид, но чхать я хотел на то, что там у вас. Right tool for the right job. Если вам нужна экстрапроизводительность — хоть на асме пишите. Но я как-то ушел из компании, в которой упоротые С++-сники писали рест-бекенд 6 месяцев, который на Go я переписал за сутки. Но это особенная каста — они столько лет шли к тому, чтобы дойти до уровня "могу писать софт, который не течет", что не могут просто так взять и перейти на другой, более адекватный для данной задачи язык, ну и плюс чувство элитарности. Это же подумать только — 5 лет в универе, плюс 3-5 лет практического опыта — это просто чтобы мочь написать сервачок, который не течет и хотя бы 10к держит. Это, блин, 10 лет жизни. Вобщем, с ними всё тяжко, и выбирать нужный инструмент для нужной задачи там, как правило, не умеют. У вас кстати это тоже чувствуется по комментариям, но могу ошибаться.


                                                                                                Хотя, возможно, это мой bias как уже давно знающего человека.

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


                                                                                                Конкретно мне это не сильно мешает писать на хаскеле вполне себе полезный и используемый код.

                                                                                                Не спорю. Пока пишешь для себя — можно хоть на своем собственном языке писать и зашифровывать на лету своим же шифром. Только программирование — это социальное занятие, и такие вещи как "сколько времени нужно новому человеку, чтобы точно построить модель программы у себя в голове, читая код", и какая когнитивная нагрузка при чтении, и как легко находить программистов под этот язык, и "добавленная сложность", который этот язык приносит, и как просто в этом языке делать тесты и бенчмарки и документацию, и сколько времени уходит на споры про "тот стиль или другой" и "сделать это таким способом или другим" — это всё matters. Только понииание вот этих вещей приходит с опытом, и в Go эти вещи стояли на первом месте. Собственно, вот эти моменты как раз все ратующие тут за дженерики TS программисты и не сильно пока вьезжают и думают, что суть программирования в том, чтобы написать меньше символов и чтобы самому понятно было.


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


                                                                                                1. raveclassic
                                                                                                  08.09.2017 00:52

                                                                                                  Каноническая классика — все кругом дебилы, один я умный! Вам бы в шараге пары вести :)


                                                                                                  1. divan0 Автор
                                                                                                    08.09.2017 00:56
                                                                                                    -1

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


                                                                                                    1. raveclassic
                                                                                                      08.09.2017 01:13

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


                                                                                                1. 0xd34df00d
                                                                                                  08.09.2017 00:59

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

                                                                                                  Я про это и говорил, а не про скорость выполнения.


                                                                                                  Вообще, у меня первые субъективные ощущения были в Go, что он чувствуется как динамический скриптовый язык, хотя на самом деле статически типизированный и быстрый (вероятно потому что я много поначалу баловалс с go run, или прямо из vim-а запуская), и из-за субсекундной компиляции это даже не чувствовалось, что там вообще этот этап есть.

                                                                                                  Жаль, REPL'а нет ни там, ни там.


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

                                                                                                  Ну вот, снова. Я понимаю, конечно, что у гошников стокгольмский синдром, когда последние лет 40 развития языков программирования прошли мимо, надо себя хоть как-то оправдать, тем более, можно пофантазировать, что ты как дропбокс, или докер, они же пользуются го, и я пользуюсь го, значит всё, элита теперь, но всё же ;)


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


                                                                                                  У вас кстати это тоже чувствуется по комментариям, но могу ошибаться.

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


                                                                                                  В сравнее с Go, который осваивается за выходные и на уровень уверенности в языке выходишь в течении месяца — это жесть, конечно.

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


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

                                                                                                  Не для себя. В продакшене используемый и полезный.


                                                                                                  Удивительно, но хаскелистов таки более одного, и споров за стиль не возникает, равно как и проблем с въезжанием в чужой код, включая тот, который делает всякую GHC.Generics-магию.


                                                                                                  1. divan0 Автор
                                                                                                    08.09.2017 01:04

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

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


                                                                                                    Не для себя. В продакшене используемый и полезный.

                                                                                                    Сколько людей работают над кодом? Сколько open-source проектов у вас? Как легко новым людям в них начать контрибьютить? Как часто вы пишете weekend-проекты, чтобы протестировать идею и, если удачна, что-то из нее сделать большее?


                                                                                                    Удивительно, но хаскелистов таки более одного, и споров за стиль не возникает,

                                                                                                    Вот именно, что удивительно.


                                                                                                    1. 0xd34df00d
                                                                                                      08.09.2017 01:11

                                                                                                      Вы же понимаете, что это лишь ваша фантазия, ибо реального способа у вас нет, пока вы не сможете сказать «я знаю язык А также хорошо, как и Б и могу сравнить».

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


                                                                                                      Сколько людей работают над кодом?

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


                                                                                                      Сколько open-source проектов у вас?

                                                                                                      Хрен знает.


                                                                                                      Как легко новым людям в них начать контрибьютить?

                                                                                                      Тяжело. В основном потому, что в опенсорсе у меня всякое нинужно.


                                                                                                      Как часто вы пишете weekend-проекты, чтобы протестировать идею и, если удачна, что-то из нее сделать большее?

                                                                                                      На той работе, за которую мне платят деньги, формат немного другой.


                                                                                                      1. divan0 Автор
                                                                                                        08.09.2017 01:20

                                                                                                        Я могу сравнить с чужими бизнес-планами,

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


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

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


                                                                                                        Тяжело. В основном потому, что в опенсорсе у меня всякое нинужно.

                                                                                                        А язык, думаете, не причем?


                                                                                                        На той работе, за которую мне платят деньги, формат немного другой.

                                                                                                        Не разрешают на выходных кодить?


                                                                                                        1. 0xd34df00d
                                                                                                          08.09.2017 01:27

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

                                                                                                          А бекенд-сервис тот вы на плюсах писали? Или чего ж вы тогда сравниваете с тем, что и как другие люди делали?


                                                                                                          Об этом и речь. Go — это для кодовых баз, над которыми потенциально работает куча людей.

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


                                                                                                          Им нужна ясность, и чем меньше мусора когнитивного, тем лучше.

                                                                                                          Не про Go, увы.


                                                                                                          А язык, думаете, не причем?

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


                                                                                                          Не разрешают на выходных кодить?

                                                                                                          И палкой бьют, если раньше 8 домой ухожу.


                                                                                                          Да не, просто на выходных я либо кожу… кодю… кодирую что-то своё, либо отдельного проекта под идею не нужно, она вполне пробуется уже в рамках рабочего имеющегося проекта.


                                                                                                          1. divan0 Автор
                                                                                                            08.09.2017 01:36

                                                                                                            А бекенд-сервис тот вы на плюсах писали? Или чего ж вы тогда сравниваете с тем, что и как другие люди делали?

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


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

                                                                                                            Это должна быть норма ежедневная, а не "опыт такой у меня был по молодости".


                                                                                                            Им нужна ясность, и чем меньше мусора когнитивного, тем лучше.
                                                                                                            Не про Go, увы.

                                                                                                            Именно про Go, к счастью.


                                                                                                            1. 0xd34df00d
                                                                                                              08.09.2017 01:38

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

                                                                                                              Значит, вы просто не выучили плюсы достаточно :)


                                                                                                              Это должна быть норма ежедневная, а не «опыт такой у меня был по молодости».

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


                                                                                                              1. divan0 Автор
                                                                                                                08.09.2017 01:41

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

                                                                                                                Но вы же никогда не признаете, что в этом львиная доля заслуги языка, правда? :)


                                                                                                                Значит, вы просто не выучили плюсы достаточно :)

                                                                                                                У меня врождённая аллергия на переусложненные вещи. Мне они просто не заходят, в какой-то момент я понимаю абсурд происходящего и мозг начинает искать альтернативы. С C++ долго альтернативы под мои критерии особой и не было, и у меня было несколько лет фрустрации от осознания, как всё печально.


                                                                                                                1. 0xd34df00d
                                                                                                                  08.09.2017 02:32

                                                                                                                  Но вы же никогда не признаете, что в этом львиная доля заслуги языка, правда? :)

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


                                                                                                                  К сожалению, остальные ещё хуже в той области, что мне интересна. Вот, может, Rust взлетит...


                                                                                                        1. VolCh
                                                                                                          08.09.2017 02:51

                                                                                                          Им нужна ясность, и чем меньше мусора когнитивного, тем лучше.

                                                                                                          А предметная область входит в мусор?


                                                                                                          1. divan0 Автор
                                                                                                            08.09.2017 02:53

                                                                                                            А предметная область входит в мусор?

                                                                                                            Нет, предметная область это essential complexity. Нагрузка, привносимая языками и тулзами, которые мы выбираем — это accidental complexity.


                                                                                                            С первой нужно считаться, от неё, как правило, не уйти. Вторую нужно уменьшать настолько насколько это возможно.


                                                            1. 0xd34df00d
                                                              07.09.2017 19:50

                                                              Ещё один мой ответ про разные деревья-хешмапы даже не в рамках трёх команд, а одной, вам тоже уже не интересен?


                                                              1. raveclassic
                                                                07.09.2017 20:08

                                                                Не интересны не то, что структуры данных, не интересна даже ущербность "DI"


                                                1. rraderio
                                                  07.09.2017 17:21

                                                  Супер, так опишите проблему, для которой вы разрабатываете решение.

                                                  Нам надо сделать API для добавления продуктов, у нас много продуктов, но они все отличаются только одним полем, поле quantity(type, value), у одних это (kg, double) у других (pieces, long) и (liters, double). С дженериками мы сделаем один класс и по классу для всех quantity.

                                                  Как это будет в go?

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

                                                  Вам продакт менеджер так и сказал?


                                                  1. raveclassic
                                                    07.09.2017 17:25

                                                    Вы сейчас классами травмируете психику го-почитателя. Для постановки задачи хватит и дженерик-интерфейсов :)


                                                  1. rraderio
                                                    07.09.2017 17:32

                                                    Дополню. С дженериками мы сделаем один класс и по классу для всех quantity и один метод save


                                                    1. divan0 Автор
                                                      07.09.2017 17:41

                                                      Отлично, в Go вы сделаете три типа для продуктов:


                                                      type Product struct {
                                                         CommonField1 int64
                                                          ...
                                                         CommonFieldN int64
                                                      }
                                                      
                                                      type ProductType1 struct {
                                                          Product
                                                          Kilograms float64
                                                      }
                                                      
                                                      type ProductType2 struct {
                                                          Product
                                                          Pieces int64
                                                      }
                                                      
                                                      type ProductType3 struct {
                                                          Product
                                                          Liters float64
                                                      }

                                                      Далее, поняв, что все эти продукты объединяются только одной общей операцией Save, создаете интерфейс, с которым будет уже работь функция общающаяся с базой или куда вы там сейвите:


                                                      type Saver interface {
                                                          Save() error
                                                      }

                                                      и реализовываете этот интерфейс для каждого типа, учитывая его особенности:


                                                      func (p *Product1) Save() error {
                                                          // save to whatever, serialize, convert, check overflows, etc
                                                      }
                                                      
                                                      func (p *Product2) Save() error {
                                                          // save to whatever, serialize, convert, check overflows, etc
                                                      }
                                                      
                                                      func (p *Product3) Save() error {
                                                          // save to whatever, serialize, convert, check overflows, etc
                                                      }

                                                      и дальше пользуете это всё вместе:


                                                      func (*DB) StoreProduct(s Saver) {
                                                          db.Insert(s.Save())
                                                      }
                                                      ...
                                                      prod1 := &Product1{Kilograms: 13.123}
                                                      prod2 := &Product2{Pieces: 13}
                                                      prod3 := &Product3{Liters: 13.123}
                                                      
                                                      db.StoreProduct(prod1)
                                                      db.StoreProduct(prod1)
                                                      db.StoreProduct(prod1)

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


                                                      UPD. В Save() там скорее всего будет код, который возвращает SQL или подобное, ну или который напрямую в базу лезет, но это менее красиво. Ну вы поняли.


                                                      Какие будут вопросы?


                                                      1. SirEdvin
                                                        07.09.2017 17:43
                                                        -1

                                                        Вам понравится Brainfuck. В нем минимально необходимое количество фич для разрабатывания программ.


                                                        1. divan0 Автор
                                                          07.09.2017 17:44
                                                          -1

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


                                                      1. rraderio
                                                        07.09.2017 17:48

                                                        Какие будут вопросы?

                                                        Понятно что можно сделать всё только имея структуры и функции, но если этих quantity у вас будут не 3 а 10, 20, с дженериками я просто добавлю 10, 20 маленьких классов и всё. В go же надо добавить не только новые структуры но и новые методы. Это по суть и цели дженериков.


                                                        1. divan0 Автор
                                                          07.09.2017 17:52

                                                          Понятно что можно сделать всё только имея

                                                          Кто-то тут ещё недавно кричал про "фееричный факап", а теперь "понятно".


                                                          структуры и функции

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


                                                          но если этих qunatity у вас будут не 3 а 10, 20, с дженериками я просто добавлю 10, 20 маленьких классов и всё.

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


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


                                                          1. rraderio
                                                            07.09.2017 17:57

                                                            Кто-то тут ещё недавно кричал про «фееричный факап»
                                                            Вы меня с кем-то путаете

                                                            Нет, структур и функций мало.

                                                            Но сделать можно и только с ними. Вот видите, вы сами написали что мало. Поэтому многие просят дженерики, потому что мало.

                                                            Если у вас добавилось одно свойство, вы будете добавлять новый класс?

                                                            Класс, который по сути структура.


                                                            1. divan0 Автор
                                                              07.09.2017 18:02

                                                              Вы меня с кем-то путаете

                                                              Потому и написал "кто-то" — тут сложно трекать, кто что написал. Но в этой ветке буквально пару постов выше было.


                                                              Вот видите, вы сами написали что мало. Поэтому многие просят дженерики, потому что мало.

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


                                                              Класс, который по сути структура.

                                                              Ок. в Go вам не нужно будет добавлять новую структуру, если добавляется новое поле.


                                                              1. rraderio
                                                                07.09.2017 18:05

                                                                Для чего в примере выше вам дженерики?

                                                                Для того чтобы написать метод save один раз

                                                                если добавляется новое поле

                                                                Не новое поле, а новый тип quantity, т.е новый Product4


                                                              1. raveclassic
                                                                07.09.2017 18:59

                                                                Кто-то тут ещё недавно кричал про "фееричный факап", а теперь "понятно".
                                                                Потому и написал "кто-то" — тут сложно трекать, кто что написал.

                                                                А что "понятно"-то? :) Писать можно хоть на бейсике и вполне себе сложные вещи. Но никто ж (почти) не пишет. Можно писать и на сях. Но Go же появился.
                                                                Вот только все эти "дурни, не видящие света в потемках, ибо есть go", рыдающие и продолжающие жевать кактус всех этих джав и шарпов, и их создатели внушают куда больше доверия.


                                                                1. divan0 Автор
                                                                  07.09.2017 19:29

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

                                                                  Ну да, столько фич. Сразу видно — можно доверять. Это так забавно, такое слышать от живого человека. :)


                                                                  1. raveclassic
                                                                    07.09.2017 19:37

                                                                    Слушайте, я не понимаю, что вообще вы делаете в этом топике и зачем делаете такие переводы? Идите пишите на своем убогом go, срезая все задачи за "неимением надобности" :) Ну правда, избавьте людей от этого цирка


                                                                    1. raveclassic
                                                                      07.09.2017 19:42
                                                                      +1

                                                                      Видимо, правду люди говорят, гошники хуже джунов-джаваскриптеров.


                                                                      1. divan0 Автор
                                                                        07.09.2017 19:50

                                                                        Видимо, правду люди говорят, гошники хуже джунов-джаваскриптеров.

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


                                                                        1. raveclassic
                                                                          07.09.2017 20:22

                                                                          Я боюсь встретить людей, которым вы мозги ломаете. Они ж неадекватые совсем должны быть… =(


                                                                    1. divan0 Автор
                                                                      07.09.2017 19:47

                                                                      Слушайте, я не понимаю

                                                                      Зная ваш бекграунд и убеждения о написании софта, я в вашем непонимании ни капли не сомневаюсь. Вы даже не понимаете, что вы пишете — не то API для продуктов, не то бинарные деревья для команд. Наверное на TypeScript это одинаково запутанно выглядит, поэтому вы и запутали себя и других.


                                                                      Не берите в штат никого больше.


                                                                      зачем делаете такие переводы

                                                                      Какие переводы?


                                                                      А вы, к слову, что полезного делаете, кроме как комментируете чужие посты и светите своим невежством? Это вы так TS-сообщество популяризируете?


                                                                      Ну правда, избавьте людей от этого цирка

                                                                      Я в этом цирке просто зритель в первых рядах. Но вы не останавливайтесь, антракт ещё не скоро.


                                                                      1. raveclassic
                                                                        07.09.2017 20:12

                                                                        Зная ваш бекграунд

                                                                        Вы знаете мой бекграунд? Вы за мной следите?


                                                                        Вы даже не понимаете, что вы пишете — не то API для продуктов, не то бинарные деревья для команд

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


                                                                        Какие переводы?

                                                                        Вот эта "статья" перевод


                                                                        А вы, к слову, что полезного делаете, кроме как комментируете чужие посты и светите своим невежством?

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


                                                                        Я в этом цирке просто зритель в первых рядах. Но вы не останавливайтесь, антракт ещё не скоро.

                                                                        Смотрите на здоровье, может толк будет :)


                                                                1. divan0 Автор
                                                                  07.09.2017 19:33

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


                                                                  весь обьект продукта надо сохранить в базу

                                                                  Я вас путаю, или вы вместе работаете?


                                                      1. 0xd34df00d
                                                        07.09.2017 20:03

                                                        В других языках написание всех этих Save (и прочих, когда вам потребуется их обновлять, выбирать или удалять) можно автоматизировать. От плюсов (да, там нужно будет руками сделать что-то вроде BOOST_FUSION_ADAPT_STRUCT для структуры, но единожды для структуры, а не для каждой пары (структура, метод), и пропозалы на компилтайм-рефлексию/метаклассы уже давно есть и обсуждаются) до хаскеля, где достаточно сделать deriving (Generic, YourDBAccessTypecalss), а компилятор выведет все нужные generic-вещи, а реализация вашего тайпкласса по умолчанию их использует для, собственно, всей работы с БД.


                                                  1. divan0 Автор
                                                    07.09.2017 17:32
                                                    -1

                                                    Нам надо сделать API для добавления продуктов, у нас много продуктов, но они все отличаются только одним полем, поле quantity(type, value), у одних это (kg, double) у других (pieces, long) и (liters, double). С дженериками мы сделаем один класс и по классу для всех quantity.

                                                    Ну наконец-то! Давайте ваш биткоин ключ, отблагодарю за труды :)


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


                                                    1. rraderio
                                                      07.09.2017 17:37
                                                      +1

                                                      А что с этим Quantity нужно делать дальше?

                                                      весь обьект продукта надо сохранить в базу


                                                1. 0xd34df00d
                                                  07.09.2017 19:47

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

                                                  А ваша цель — максимально эффективно использовать все ядра процессора? Считайте Мандельброта на каждом ядре, тоже мне вопрос.


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


                                                  Скрытый текст

                                                  Узнаёте стиль?


                                                  1. divan0 Автор
                                                    07.09.2017 19:54

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

                                                    Ну это же очевидно. Вот смотрите, визуализация работы Node.JS программ: http://imgur.com/jqsdofy


                                                    Понятно, или объяснять ещё?


                                                    А ваша цель — максимально эффективно использовать все ядра процессора?

                                                    А ваша цель — минимально эффективно их использовать? Узнаете стиль?


                                                    1. 0xd34df00d
                                                      07.09.2017 20:17

                                                      Понятно, или объяснять ещё?

                                                      Если решает бизнес-задачу, то так ли это важно?


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


                                                      А ваша цель — минимально эффективно их использовать?

                                                      Моя цель — решить бизнес-задачу. Или у вас бизнес ставит задачи «максимально эффективно использовать ядра процессора»? Прям так в жире и висят задачи от бизнеса?


                                                      Узнаете стиль?

                                                      Неа.


                                            1. 0xd34df00d
                                              07.09.2017 19:44

                                              Жаль, я думал вы будете первый, кто внятно даст ответ на такой простой вопрос.

                                              То есть, мой ответ снова не засчитывается?


                                              1. divan0 Автор
                                                07.09.2017 19:56

                                                То есть, мой ответ снова не засчитывается?

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


                                                1. 0xd34df00d
                                                  07.09.2017 20:15

                                                  Что значит «мне, возможно, захочется»? На разных типах данных я гонял, другие формулы подставлял.


                        1. 0xd34df00d
                          06.09.2017 20:52
                          -1

                          Окей, как в Haskell запустить горутину

                          Горутину — никак, это ж не го. Гринтред — через forkIO или кучу прекрасных примитивов из пакета async. Закинуть чистую задачу в пул — par из стандартной библиотеки, parMap rdeepseq и друзья из Control.Paralell.Strategies, runPar . parMap и друзья из Control.Monad.Par.


              1. divan0 Автор
                06.09.2017 15:04
                -1

                мне не нужен такой язык, увы.

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


                1. rraderio
                  06.09.2017 16:02
                  +1

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

                  Нет, вы пишите статьи о том что node не нужен


                  1. divan0 Автор
                    06.09.2017 16:31
                    -1

                    Нет, вы пишите статьи о том что node не нужен

                    Я уже привык к неадеквату тут в комментариях, но это хит. Покажите мой такой пост.


                    Данный пост, к примеру, это перевод интервью разработчика Node.js, с его мыслями про Go. Перевод. Интервью. Про Go.


                    1. rraderio
                      06.09.2017 16:38
                      +1

                      Вот вы перевели, с какой целью?


                      1. divan0 Автор
                        06.09.2017 16:47
                        -1

                        Дать её прочесть тем, кто не читает статьи на английском. А вы с какой целью комментируете?


                        1. rraderio
                          06.09.2017 17:03
                          +1

                          Узнать что-то новое


  1. nwalker
    04.09.2017 17:55
    +7

    Этот фрагмент меня поражает поразительной незамутненностью интервьюируемого.


    Насколько же нужно не смотреть вообще по сторонам и не интересоваться ничем кроме своей песочницы, чтобы открыть для себя "блокирующий стиль поверх грин-тредов" с SMP-планировщиком в Go в 2012? Я не удивлюсь, если Дал лет через пять откроет для себя, скажем, Elixir.


    1. rraderio
      05.09.2017 09:33

      А что такого есть в Elixir?


      1. nwalker
        05.09.2017 12:38
        +2

        Все то же самое, только по-другому. Местами получше, местами похуже. Язык богаче, косяки есть, но не ужасают. Тулсет неплох.
        Рантайм — BEAM — сложно сравнить, просто принципиально другой и обладает рядом killer features, которых нет вообще ни у кого.


        1. vintage
          05.09.2017 14:02

          Можно по подробнее про фишки-убийцы?


          1. rraderio
            05.09.2017 14:25

            не та ветка


            1. vintage
              05.09.2017 14:34
              -5

              Комплекс вахтёра?


          1. nwalker
            05.09.2017 17:50

            Ну погуглите Erlang killer features. Изоляция данных и ошибок, например. Вообще механика каскадирования ошибок. Per-actor GC. Крутой preemptive планировщик c work stealing. Очень крутые возможности интроспекции, когда ты можешь своими руками потрогать изнутри работающую систему.
            Еще есть hot code replacement, которым, впрочем, мало кто пользуется, потому что это мало кому реально нужно.
            Порты как метод FFI весьма приятны.
            Distribution с его сетевой прозрачностью, к которому я отношусь довольно двояко, но который все же есть и работает из коробки до поры до времени. Рано или поздно приходится начинать думать, но это везде так.


        1. rraderio
          05.09.2017 14:30
          -1

          Можно про косяки поподробнее?


          1. nwalker
            05.09.2017 18:24

            Ну, в нем есть не столько косяки, сколько некоторая неконсистентность. Например, вот взять дурацкий синтаксис вызова анонимных функций fun_variable.(:a, :b, :c).


            Или вот эти приколы с proplist syntax:


            Interactive Elixir (1.4.4) - press Ctrl+C to exit (type h() ENTER for help)
            iex(1)> [1, 2, 3, a: 4, b: 5]
            [1, 2, 3, {:a, 4}, {:b, 5}]
            iex(2)> [1, 2, 3, a: 4, b: 5, 6]
            ** (SyntaxError) iex:2: syntax error before: 6
            
            iex(2)> a = [1, 2, 3, a: 4, b: 5]
            [1, 2, 3, {:a, 4}, {:b, 5}]
            iex(3)> [c: 6 | a]
            ** (CompileError) iex:3: undefined function |/2
                (stdlib) lists.erl:1353: :lists.mapfoldl/3
                (stdlib) lists.erl:1354: :lists.mapfoldl/3
            iex(3)>

            или вот такие истории с мапами


            iex(4)> b = %{:a => 5}
            %{a: 5}
            iex(5)> %{b | :a => 5}  
            %{a: 5}
            iex(6)> %{b | :a => 6}
            %{a: 6}
            iex(7)> %{b | :a => 6, b => 7}
            ** (KeyError) key %{a: 5} not found in: %{a: 6}
                (stdlib) :maps.update(%{a: 5}, 7, %{a: 6})
                (stdlib) erl_eval.erl:255: anonymous fn/2 in :erl_eval.expr/5
                (stdlib) lists.erl:1262: :lists.foldl/3
            iex(7)> %{:a => 6, b => 7 | b}
            ** (CompileError) iex:7: undefined function |/2
                (stdlib) lists.erl:1353: :lists.mapfoldl/3
                (stdlib) lists.erl:1354: :lists.mapfoldl/3
                (stdlib) lists.erl:1353: :lists.mapfoldl/3

            или proplist syntax который работает только для ключей-атомов


            iex(7)> ["c": 6]                 
            [c: 6]
            iex(8)> ["c": 6][:c]
            6

            Если идти от языка к стандартной библиотеке, есть вот такое


            iex(9)> ["c": 6]["a"]
            ** (ArgumentError) the Access calls for keywords expect the key to be an atom, got: "a"
                (elixir) lib/access.ex:255: Access.fetch/2
                (elixir) lib/access.ex:269: Access.get/3

            Причем, это поведение изменить никак нельзя. because fuck you, that's why
            Были еще какие-то шероховатости, уже не помню.


            А вот если идти дальше, вот мы видим Plug и Phoenix, и вот они — редкостное говно во целому ряду причин.


  1. jehy
    04.09.2017 21:40
    +11

    Разработчики на Go мне яро напоминают воинствующих мусульман в мире IT. Аллах сказал им писать на Go, и дальше они под это будут агрессивно проталкивать любую ложь и переворачивать любую истину. За всё время не встречал более упоротых поклонников технологии, чем эти ребята. Подозреваю, там где-то есть зомбирующие коды и мануалы.


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


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


    1. divan0 Автор
      04.09.2017 22:27
      -8

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

      Типичная речь хейтера.


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

      Эпизод, действитльно, интересный, но мне было интересно перевести именно часть про Go для Хабра. Я знаю многих людей, которые пишут на node.js, просто потому, что даже не знают про другие технологии. Подобная статья должна, как минимум, привлечь их внимание, а дальше дело техники. Ведь в 2017-м, действительно, причин не писать серверы на Go очень мало (и это не Аллах говорит, а здравый прагматичный смысл).
      А то, что вас это задевает лично, и вы бросаетесь людей называть хейтерами — сочувствую.


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

      Теперь понятно, спасибо. Очень объективно и доступно объяснили, а то я думал, что он имел ввиду, то что сказал в интервью. А оно вот оказывается как, просто новое хотел попробовать.


      1. Nakosika
        04.09.2017 23:54
        +2

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


      1. jehy
        05.09.2017 00:47
        +1

        Я знаю многих людей, которые пишут на node.js, просто потому, что даже не знают про другие технологии.

        Если они не знают про другие технологии, то для их веб магазина и PHP отлично сойдёт. Да и писать статью для этих людей в хабр это какое-то лукавство.


        1. divan0 Автор
          05.09.2017 00:56
          +2

          Да и писать статью для этих людей в хабр это какое-то лукавство.

          Один мой бывший коллега рассказал, что решил попробовать Go на предыдущем проекте после прочтения пары статей о Go на Хабре. В частности одна из них была про то, как после переписывания с Node на Go уменьшили количество серверов с 60 до 2 :) Так что я с вами не согласен.


          1. muxrim
            05.09.2017 11:46
            +1

            Вот этот?


            1. divan0 Автор
              05.09.2017 11:48
              -1

              Хм, может быть, но тут с Ruby переходили.


    1. SirEdvin
      05.09.2017 14:07
      -3

      Видели ли вы фанатов nodejs? У golang хотя бы есть неоспоримые преимущества)


      1. jehy
        05.09.2017 14:45
        +1

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


    1. ZurgInq
      05.09.2017 14:12
      +3

      Разработчики на Go мне яро напоминают воинствующих мусульман в мире IT.

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


      1. divan0 Автор
        05.09.2017 14:21
        -1

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


      1. CuredPlumbum
        05.09.2017 14:37

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

        Примитивизм Go привлекает меня тем, что наконец-то можно писать в любимом стиле «что вижу, то пою». Без факторей, декораторов и IoC-контейнеров с AOP-ями.

        Главным образом, Go сравниваю с Java, C#. Сравнения — не в пользу последних. Видно, что Go создан для корпоративной разработки, оттуда многие «странные» решения типа ошибки компиляции при неиспользуемом импорте.


        1. SirEdvin
          05.09.2017 14:47
          +1

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


          1. divan0 Автор
            05.09.2017 15:00

            Как раз нет. Go не создан для корпоративной разработки

            Как раз да. Go создан для корпоративной разработки. Многие решения в нём очень четко принимались из расчета работы в больших командах (1000+ человек) и больших проектах. Google всё таки, прежде всего, для своей продуктивности язык хотел, а то что и остальным он хорошо зашел это неслучайный побочный эффект.


            1. SirEdvin
              05.09.2017 15:11
              +3

              Ладно. jehy, думаю, вы победили. В этом комменте прекрасно все, начиная от безумного размера команды (1000+, вы серьезно? :)), заканчивая формулировкой. А ведь язык молодой, ему еще жить и жить.


              О да. Команда на 1000+ человек, а у нас в языке нужно самому пробрасывать исключения, и все его преимущества сыпятся, когда растет или стек вызовов или сложность проекта, потому что вместо кода пишутся всякие if err!=nil, шаблонные методы для разных типов, потому что шаблонные типы слишком сложно. Это типо команда из 1000+ синьеров?)


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


              Не говоря уже о том, что команды больше чем в 1000 человек не существует и никогда не будет существовать. Это просто управленческий ад. Даже если у вас такая появится, вы все равно будете делить ее на подразделения, которые будут работать независимо и потом кто-то один будет сливать весь код.
              Хотя о чем это я. Нет ни одного такого проекта :)


              Мне интересно, это продолжительное написание кода на golang приводит к таким странным деформациям и упрощенному видению процессов разработки?


              1. divan0 Автор
                05.09.2017 15:22
                -2

                В Google каждый может изменить код в проектах других команд, поэтому потенциально над одним и тем же кодом могут работать больше 1000 людей. Но вы не останавливайтесь, разглагольствуйте. :)


                1. SirEdvin
                  05.09.2017 15:23
                  +1

                  Каждый разработчик потенциально может внести изменение в ядро linux, так что у linux больше 1кк разработчиков?
                  Так это не работает, простите.


                  1. divan0 Автор
                    05.09.2017 16:16
                    -1

                    так что у linux больше 1кк разработчиков?

                    Вы хотите развести очередной спор на 100 комментариев о кого, считать разработчиком, а кого нет? В ядре Linux больше 10k разработчиков, да. Как там IDE, загрузилась уже?


                    1. SirEdvin
                      05.09.2017 16:21
                      +1

                      Ну так это же важно для вас. Мне то все равно, а вот для вас важно, что Golang разрабатывался для команд из аж 1000 человек.


                      У меня прогрузка зависит от количестве комментариев на хабре. Я вот три дня загружаю и два дня пишу код.


                      1. divan0 Автор
                        05.09.2017 16:51

                        а вот для вас важно, что Golang разрабатывался для команд из аж 1000 человек.

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


                        Но вам лучше знать, конечно.


                        1. SirEdvin
                          05.09.2017 16:59
                          +2

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

                          Вон автор nodejs утверждал, что открыл асинхронное программирование.


                          1. divan0 Автор
                            05.09.2017 17:16

                            Вон автор nodejs утверждал, что открыл асинхронное программирование.

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


                            1. SirEdvin
                              05.09.2017 17:16
                              +1

                              У вас осталась так же проблемы. Вы верите.


                              1. divan0 Автор
                                05.09.2017 18:27

                                Я сделаю код реальнее, что бы вы мне поверили
                                У вас осталась так же проблемы. Вы верите.

                                Это ваша проблема, увы.


          1. CuredPlumbum
            05.09.2017 15:15
            +3

            Как раз нет. Go не создан для корпоративной разработки, и именно это многим в нем нравится.

            Полагаю, вы в курсе, что Go создан Google? Полагаю, вы догадываетесь, что Google его создал и развивает для своей корпоративной разработки. Пожалуйста, посмотрите первоисточник:
            https://talks.golang.org/2012/splash.article

            В частности, оттуда:
            Go is a programming language designed by Google to help solve Google's problems, and Google has big problems.

            Как мы видим, «big problems» это не совсем то, что вы обозначили как «простые функциональные компоненты». Кстати, что это за понятие?

            Он создан для простых функциональных компонентов, но как только вам приходится писать на нем большие приложения, все эти «удобные» решения превращаются в то, что вы делаете из go язык, к которому вы привыкли.

            Не понял вашу мысль. Кто что из чего делает?


            1. vintage
              05.09.2017 15:25
              +3

              Гугл не занимается корпоративным софтом.


              1. CuredPlumbum
                05.09.2017 15:33

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


                1. SirEdvin
                  05.09.2017 15:40

                  Там внизу есть список типов корпоративного софта:


                  Accounting software
                  Billing Management
                  Business intelligence
                  Business process management
                  Content management system (CMS)
                  Customer relationship management (CRM)
                  Database
                  Enterprise resource planning (ERP)
                  Enterprise asset management (EAM)
                  Supply chain management (SCM)
                  Backup software


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


                  1. CuredPlumbum
                    05.09.2017 21:00

                    То есть вы серьёзно полагаете, что Google ничего подобного не создаёт?!


                    1. raveclassic
                      05.09.2017 21:08

                      А вы примеры приведите


                      1. CuredPlumbum
                        05.09.2017 22:17

                        cloud.google.com

                        gsuite.google.com

                        Ну и билинг они для этих и других сервисов вряд ли покупали.


                        1. SirEdvin
                          05.09.2017 22:45
                          +1

                          Ну и билинг они для этих и других сервисов вряд ли покупали.

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


                          Почему google не может использовать сторонние продукты для огранизации работы в своей компании? Почему google не может использовать, например, jira? Я думаю, что некоторые команды в google вполне так делают.


                          Или google избранная компания, которая каждый продукт пишет с нуля?


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


                          1. CuredPlumbum
                            05.09.2017 23:11

                            Выше попросили привести примеры. Я привёл. И предположил, что биллинг они написали для себя сами. На их месте я бы однозначно так и сделал бы.

                            На чём и как написаны и переписаны сервисы, — я без понятия.


            1. SirEdvin
              05.09.2017 15:27
              +2

              Полагаю, вы в курсе, что Go создан Google? Полагаю, вы догадываетесь, что Google его создал и развивает для своей корпоративной разработки. Пожалуйста, посмотрите первоисточник:

              Если я правильно прочитал, то Google достал legacy код на С/С++ и они решили сделать себе С с человеческим лицом. Вот только вы не Google. И вы же не пишете на C свои веб-приложения? А из перечисленных проблем половины вообще не существует в других языках. Вся статья о том, почему нужно использовать go вместо C, ну и я с этим согласен.


              Как мы видим, «big problems» это не совсем то, что вы обозначили как «простые функциональные компоненты». Кстати, что это за понятие?

              Это я так неправильно назвал микросервисы. Но как я понял из статьи, big problems — оно больше под поддержку уже существующий решений, так как инфрастуктура С в целом очень и очень разнообразна и способов сделать одну вещь может сущестовать десятки. Плюс описанные в статье проблемы C. Про сложность задач тут не говорится, как я понимаю.


              Не понял вашу мысль. Кто что из чего делает?

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


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


              1. CuredPlumbum
                05.09.2017 21:30
                +1

                Если я правильно прочитал, то Google достал legacy код на С/С++ и они решили сделать себе С с человеческим лицом.
                Нет, неправильно. Там же в первой главе, сразу:
                Go was designed and developed to make working in this environment more productive. Besides its better-known aspects such as built-in concurrency and garbage collection, Go's design considerations include rigorous dependency management, the adaptability of software architecture as systems grow, and robustness across the boundaries between components.

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

                Когда вы пишите большой проект на golang, вам приходится заниматься такими штуками, которые в других языках работают сами по себе.
                А есть штуки, которые в Go есть, а в других языках ими нужно заниматься.
                Я имел ввиду, что простота синтаксиса работает в обе стороны. Чем больше у вас кода, тем больше возникает дублирования, потому что из-за простоты синтаксиса вам от нее не избавится. И приходит время, когда дублирования очень много.
                Код на Go для меня понятнее, чем на Java или C#. А дублирование кода или нет — дело десятое.


                1. SirEdvin
                  05.09.2017 22:41
                  -1

                  Код на Go для меня понятнее, чем на Java или C#. А дублирование кода или нет — дело десятое.

                  Для меня наоборот. Или вы сравниваете простой написанный сервис на golang и что-то монструозное со spring на Java? Так дело не в сложности языка, а в сложности фреймоворка. На golang ситуация лучше не станет.


                  А есть штуки, которые в Go есть, а в других языках ими нужно заниматься.

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


                  1. CuredPlumbum
                    06.09.2017 10:58
                    +1

                    Для меня наоборот. Или вы сравниваете простой написанный сервис на golang и что-то монструозное со spring на Java? Так дело не в сложности языка, а в сложности фреймоворка. На golang ситуация лучше не станет.
                    Да, я сравниваю Go с Java или C#. И дело не только (да и не столько) в Spring. Просто, Spring — это такой мейнстрим в Java размером с Амазонку.

                    Все современные языки общего назначения (а не общего, — тем более), идут в комплекте со своей моделью проектирования. Ну, или, если хотите, Java-way, C#-way, Go-way, Ruby-way etc.

                    Это неустранимые особенности языков. У Java, кроме злоупотреблений с рефлексией и манипуляцией байт-кодом, главный бич: многословность, сиречь — тиражирование сущностей без необходимости.

                    Подскажите? Я знаю только статический анализ и форматирование (впрочем, статическим анализом вам все равно нужно будет занятся). Если вы походите с туза и скажите про асинхронищину, то есть тоже нужно заниматься, как и в любом другом языке, в силу ее сложности.
                    А с чем сравниваем? Скажу сразу, что сравнивать Go и Python бессмысленно. Это языки из разных ниш.


                    1. SirEdvin
                      06.09.2017 13:54

                      Это неустранимые особенности языков. У Java, кроме злоупотреблений с рефлексией и манипуляцией байт-кодом, главный бич: многословность, сиречь — тиражирование сущностей без необходимости.

                      В случае Java вам из "злоупотреблений с рефлексией и манипуляцией байт-кодом" и "многословность" стоит выбрать что-то одно, потому что первое обычно используется для решения второго. Например, Lombok.


                      Это неустранимые особенности языков. У Java, кроме злоупотреблений с рефлексией и манипуляцией байт-кодом, главный бич: многословность, сиречь — тиражирование сущностей без необходимости.

                      Проблема в том, что вы игнорируете условия, при которых у вас появляются эти проблемы. Они появляются при больших проектах. И с ними в golang вы начинаете, например, эмулировать ручками generic из Java, гоняя объекты в interface{} и обратно. В коде moby (я делал вот так grep "interface{}" -R . | grep docker | wc -l нашлось 1063 места, где используется этот интерфейс. (То есть да, а еще захватил код из vendor/docker).


                      Ну и многословноть, это так же про golang. В том же коде 1209(!!!!) строчек вида return nil, err (вместо err еще иногда бывает внезапное оборачивание err в какую-то другую ошибку, типо так: errors.Wrap(validationError{err}, "error reading labels")). Ну, то есть 3627 строчек кода, в которых просто делается проброс ошибки. Не очень многословно, правда? (А это вместе с вендорами, сейчас исправлю.


                      А с чем сравниваем? Скажу сразу, что сравнивать Go и Python бессмысленно. Это языки из разных ниш.

                      Ну, давайте сравним с C++. Компилятор возьмем gcc. Или это тоже не в область? Можно еще взять Rust или D, но я про них мало что знаю.


                      1. SirEdvin
                        06.09.2017 13:58

                        Поправлю, не 1063, а 1405 мест :)


                        1. divan0 Автор
                          06.09.2017 15:06

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


                          Но продолжайте грепать и себя убеждать. Это уже неизлечимо. ) Можете еще на 3 умножить, как вы делали чуть раньше. Будет ещё больше.


                          1. SirEdvin
                            06.09.2017 15:09
                            -1

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


                            1. divan0 Автор
                              06.09.2017 15:19

                              Обработка ошибки это "решить, что делать с ошибкой на этом уровне и дать это понимание программисту, читающему код". Отдать ошибку наверх — это тоже "обработка ошибки".


                              1. SirEdvin
                                06.09.2017 15:25

                                Зачем мне эта лишняя когнитивная нагрузка, которая заставляет меня думать "а что же тут происходит", если я и так знаю, что это поведение по умолчанию?)


                                1. divan0 Автор
                                  06.09.2017 16:45

                                  эта лишняя когнитивная нагрузка

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


                                  1. SirEdvin
                                    06.09.2017 17:05

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


                                    1. divan0 Автор
                                      06.09.2017 17:30

                                      что это работает в пределах функции, а у нас тут не фунциональщина

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


                                      1. SirEdvin
                                        06.09.2017 17:40

                                        Ну, для вас может и да. А так обычная у меня логика, мне хватило копания в коде docker и jobber, что бы понять это.


                                        А сколько кода нужно перелопатит вам, что бы дойти до идее о том, что локальное поведение не дает вам информации о программе?)


                                        1. divan0 Автор
                                          06.09.2017 18:33

                                          что бы дойти до идее о том, что локальное поведение не дает вам информации о программе?)

                                          Это та фантазия, которую вы сами выдумали, сами мне приписали и уже который комментарий подряд боретесь? Успехов.


                                          1. SirEdvin
                                            06.09.2017 18:39

                                            Жду от вас ответ, какая в этом месте используется реализация ICmd. Разумеется, не заглядывая в другие места в коде.


                                            1. divan0 Автор
                                              06.09.2017 18:46

                                              Ждите. Я уже писал, что единственная причина общения тут с вами — это накрутка количества бессмысленных комментариев. Вы очень хорошо справляетесь, продолжайте в том же духе.


                                              1. SirEdvin
                                                06.09.2017 18:47

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


                                                1. divan0 Автор
                                                  06.09.2017 19:35

                                                  Записывайте. Вы уже давно сам собой общаетесь — сами придумываете, сами интерпертируете, сами этим себе что-то доказываете.


  1. index0h
    04.09.2017 23:22
    +5

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


  1. shybovycha
    05.09.2017 06:58
    +2

    Зацепил вот этот отрывок:


    В общем, неблокирующая парадигма в Node работала очень неплохо для JavaScript, там где у вас нету потоков. И я думаю, что многие из тех проблем с callback hell, когда вам нужно прыгать в кучу разных функций чтобы закончить то, что вы делаете, в эти дни достаточно неплохо решены, с помощью async, например, который сейчас есть в JavaScript. То есть, как бы, новые версии Javascript делают жизнь немного проще. Учитывая всё это, я бы сказал, Node не лучшая система для массивных веб-серверов, я бы использовал Go для этого.

    Вот я не понял, вроде ж говорит что на новые версии ноды все хорошо налазит. Но нет, это лишь доказывает, что Go лучше. Wat.


    1. vintage
      05.09.2017 07:32

      Наличие костыля доказывает, что архитектура изначально кривая. Ведь можно было бы реализовать "волокна" и без подпорок в виде async/await.


  1. mistbow
    05.09.2017 09:29

    А как правильно организовать SEO для Angular и Go, если не использовать пререндеринг на node?


  1. Kirhgoff
    05.09.2017 09:39

    С Go есть свои проблемы — я нашел, что в отсутствии нормального IDE очень трудно рефакторить большие иерархии классов, особенно, когда она еще не устоялась и находится в процессе постоянной переработки. Прямо вот очень неудобно. Мы в проекте стараемся использовать Go только для маленьких сервисов, которые процессят данные и запуливают их дальше куда-нибудь.


    1. SirEdvin
      05.09.2017 10:55

      Даже goglang не помогает? У этим ребят отлично топовые ide.


  1. divan0 Автор
    05.09.2017 09:41
    +4

    трудно рефакторить большие иерархии классов

    Kirghoff Это был не Go, вас обманули :)


  1. ilja903
    05.09.2017 11:37
    +4

    Сравнивать компилируемые языки и интерпретируемые для веб-разработки это какой-то верх невежества. Видимо необязательно иметь широкий кругозор для того что-бы быть создателем чего-либо.
    По факту язык значит не так уж много, экосистема и киллер-фичи решают. Покажите мне джангу на го с автогенериремой админкой, миграциями и какой-нибудь cms ala django cms.


    1. divan0 Автор
      05.09.2017 11:39

      Покажите мне джангу на го с автогенериремой админкой, миграциями и какой-нибудь cms ala django cms.

      Типа такого?



  1. DarthVictor
    05.09.2017 11:39
    +2

    Добавьте голосовалку, «На какой будет следующий язык запрыгнет Раян Дал?»


    1. divan0 Автор
      05.09.2017 11:45
      -2

      Зачем?


    1. Crandel
      05.09.2017 11:46
      +3

      Через пару лет он раст увидит)))


      1. divan0 Автор
        05.09.2017 11:48
        -1

        И скажет «модель программирования в Rust намного лучше Go»? :) Ну ок, вернемся к этому комменту через 5 лет.


  1. beduin01
    05.09.2017 12:04
    +4

    Замечательный язык Go. Давайте посмотрим как в нем проверка вхождения элемента в массив выглядит:

    func stringInSlice(a string, list []string) bool {
        for _, b := range list {
            if b == a {
                return true
            }
        }
        return false
    }


    И там все через одно место…


    1. Crandel
      05.09.2017 12:08
      +1

      Что именно вас тут смущает?


      1. beduin01
        05.09.2017 12:09
        +2

        В нормальных языках это в одну строчку делается.


        1. Crandel
          05.09.2017 12:31
          +1

          Ну без женериков тут сложно сделать универсальную функцию. Их отсутствие минус для меня лично


    1. ZurgInq
      05.09.2017 13:08

      Через одно место, но в данном случае выход есть clipperhouse.github.io/gen/slice/#any


    1. divan0 Автор
      05.09.2017 13:27
      -1

      1. Что вам мешает использовать эту функцию в одну строчку?
      2. Что вам мешает использовать `strings.Contains()` из стандартной библиотеки
      3. Как именно это затрудняет написание кода?

      Я не шучу, сейчас у вас есть шанс повлиять на развитие Go, написав experience report про то как отсутствие или присутствие какой-то фичи реально мешает писать надежный код. Мне кажется, вам есть что сказать и донести до авторов Go того, что они не понимают.


      1. beduin01
        05.09.2017 13:33

        > `strings.Contains()
        Она с целочисленными массивом работать будет?
        int [] x = [1,2,3,4,5];

        >Как именно это затрудняет написание кода?
        А зачем писать лишний код?


        1. divan0 Автор
          05.09.2017 13:38
          -2

          Она с целочисленными массивом работать будет?

          Нет. это же пакет strings.


          А зачем писать лишний код?

          В Go нет многих фич и функций вроде map/reduce/filter, и это сделано сознательно, чтобы сделать язык максимально простым. Именно благодаря этому в Go такой низкий порог входа. И далеко не все приложения нуждаются в map/reduce/whatever — это все элементарнейше пишется при необходимости (или используются библиотеки, если совсем лень).


          Так что, будете писать experience report? Помогите сделать Go лучше и не через одно место :)


          1. beduin01
            05.09.2017 14:04
            +2

            >и это сделано сознательно, чтобы сделать язык максимально… примитивным
            К тому же все эти урезания лишь к лишним багам будут приводить.

            >Так что, будете писать experience report?
            Зачем? Я на Go не писал и не планирую. Я для себя не вижу ни единой задачи которую он мне позволит решать быстрее\лучше\эффективнее чем Python/D.


            1. divan0 Автор
              05.09.2017 14:08
              -1

              К тому же все эти урезания лишь к лишним багам будут приводить.

              Не будут.


              1. jehy
                05.09.2017 14:50
                +1

                Будут. Количество велосипедов прямо пропорционально количеству багов.


                1. divan0 Автор
                  05.09.2017 15:07
                  -3

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


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


                  1. SirEdvin
                    05.09.2017 15:48
                    +1

                    Не будут. Количество багов квадратично пропорционально когнитивной сложности возложенной на программиста.

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


                    1. Nakosika
                      05.09.2017 20:10

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


                      1. SirEdvin
                        05.09.2017 22:53
                        -2

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


                      1. 0xd34df00d
                        06.09.2017 00:37
                        -1

                        В функциональщине надо существенно реже мыслить в терминах стектрейсов.


    1. ewgRa
      05.09.2017 23:06

      А как это будет в Java выглядеть?


      1. vintage
        06.09.2017 09:27

        Давайте я вам лучше на D пример приведу:


        [ "foo" , "bar" , "baz" ].canFind( "foo" )


        1. ewgRa
          06.09.2017 10:11
          +1

          А что под капотом этой строчки? import?

          В Go можно тоже организовать подобное:

          type SearchableList string[]

          func (sl SearchableList) CanFind(search string)…

          и вперед, можно его юзать.

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

          Ваш пример, так как значений очень мало, проще сделать на map (ассоциативный массив), там уже есть стандартный поиск за O(1). Если же у вас много значений, то разумнее это дело хранить в сортированном виде, и юзать binary search. В sort есть Search, который Binary search производит, также там есть SearchStrings, который делает то, что в вашем примере, но на отсоритрованном массиве. То есть когда допустим ревьювер посмотрит ваш код, увидит велосипед, у него прозвенит звонок, что где-то написано неоптимально. Если вы подключите либу, аналогично.

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

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


          1. vintage
            06.09.2017 12:02
            -1

            А что под капотом этой строчки? import?

            import std.algorithm , std.stdio;
            
            [ "foo" , "bar" , "baz" ].canFind( "foo" ).writeln;
            [ 1 , 2 , 3 ].canFind( 1 ).writeln;
            
            import std.math;
            [ 1.1 , 2.2 , .3.3 ].canFind!approxEqual( 1.1 ).writeln;
            
            struct Foo { int bar; }
            [ Foo(1) , Foo(2) , Foo(3) ].canFind( Foo(1) ).writeln;

            не давать делать из коробки то, что будет работать очень неоптимально

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


            func stringInSlice(a string, list []string) bool {
                for _, b := range list {
                    if b == a {
                        return true
                    }
                }
                return false
            }


    1. Comdiv
      05.09.2017 23:58

      Беда с такими программистами, которые используют линейный поиск по массиву O(n) там, где следует использовать ассоциативный массив O(1). Потому всё и тормозит.


      1. 0xd34df00d
        06.09.2017 00:41
        +1

        Беда с такими программистами, которые асимптотику O(f(N)) используют для обоснования выбора алгоритма и структуры данных при N ? 5. Линейный поиск, особенно если массив поместится в один-два кешлайна, будет дружественнее к шине памяти и к предсказателю переходов и, вполне возможно, окажется быстрее.


        1. Comdiv
          06.09.2017 01:38
          +1

          Если Вы имеете ввиду [1, 2, 3, 4, 5], что встречается в сообщении, которое автор претензии к Go выложил в ответе собеседнику, так принадлежность к такому множеству вообще решается через битовые маски в Си-подобных языках

          0 != ((1 << n) & 62)

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

          А о чём это говорит? Что как раз нет большого смысла в однообразном способе решения, за которое так радеет автор претензии к Go, желая работать одинаково и со строками, и с числами, и с бог знает с чем ещё. Когда вместо сферических примеров в вакууме появляется настоящая задача, то всё видится несколько не так.

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


          1. 0xd34df00d
            06.09.2017 01:51

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

            Как раз есть. Потому что мне в моей практике массивы из нескольких элементов встречались не раз и не два. Может, это символ из множества разделителей (который массив символов), может, это массив идентификаторов, массив floating-point-порогов, да мало ли. Или какой-то кастомный тип данных (type-driven development, ага), который внутри, конечно, число (внутри в компьютере всё — число, в конце концов), но к числу не приводится и просто так из числа не конструируется.


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


            1. divan0 Автор
              06.09.2017 10:34

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

              И в этом один из самых недоговоренных минусов дженериков — их почти всегда переиспользуют. Люди начинают мыслить обобщениями там, где они не нужны и писать фантастическую лапшу там, где нужно сделать функцию в одну строчку с конкретным типом. Концепция design code around data летит в трубу. Зато дженерики, очень удобно, да.


              1. rraderio
                06.09.2017 10:54

                Концепция design code around data летит в трубу

                И зачем тогда в go добавили interface? Пишите только функции которые принимают данные.


                1. divan0 Автор
                  06.09.2017 11:15

                  И зачем тогда в go добавили interface?

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


                  1. rraderio
                    06.09.2017 11:20

                    чтобы очень четко отделить данные от поведения.

                    Но зачем вам поведения? у вас ведь design code around data, т.е. только данные и функции.
                    в реальной жизни у вас есть конкретные задачи, конкретные данные

                    Т.е. interface не нужен.


                    1. divan0 Автор
                      06.09.2017 11:29

                      у вас ведь design code around data

                      А у вас нет? Вы сначала code, а потом смотрите на то, с чем вы вообще работаете?


                      Т.е. interface не нужен.

                      Просто наверное жить с такой бинарной логикой.


                      1. rraderio
                        06.09.2017 11:44

                        А у вас нет? Вы сначала code

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

                        Ну а зачем тогда interface если в реальной жизни у вас есть конкретные задачи, конкретные данные?


                        1. divan0 Автор
                          06.09.2017 12:23

                          Да, я сначала делаю все на интерфейсах, а потом создаю данные

                          Ясно, а в Go наоборот. Интерфейсы добавляются только тогда, когда нужно абстрагировать поведение, но не раньше.


                          https://habrahabr.ru/post/276981/


                          1. SirEdvin
                            06.09.2017 13:39

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


                            SOLID вроде тоже не дураками придуман. От предложенного вами подхода давно отказались, как от очень неудобного.


                            1. divan0 Автор
                              06.09.2017 15:10

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


                              1. SirEdvin
                                06.09.2017 15:20
                                -1

                                б) от какого именно подхода отказались, и кто именно отказался.

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


                                Но вы правы, многолетний опыт ничего не стоит.


                                1. divan0 Автор
                                  06.09.2017 15:26
                                  -1

                                  От того, что вы предлагаете.

                                  От вашего искаженного понимания того, что описал (ничего не предлагая)


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

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


                                  1. SirEdvin
                                    06.09.2017 15:28

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

                                    Мне очень лестно, что вы приписали мне изобретение одного из широко используемых принципов ООП разработки, который нашел свое отражение в первую очередь в DI, но это не так.


                                    1. raveclassic
                                      06.09.2017 17:45

                                      Вы что, DI в Go не нужен, так как это очень сложно.


                                  1. SirEdvin
                                    06.09.2017 15:29
                                    -1

                                    От вашего искаженного понимания того, что описал (ничего не предлагая)

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


                                    1. divan0 Автор
                                      06.09.2017 18:35

                                      raveclassic SirEdvin вы, кажется, нашли друг друга. Оставляю вас наедине )


                                      1. raveclassic
                                        06.09.2017 19:19

                                        Ну погодите, инверсия зависимостей есть и в ООП-языках в виде классического DI/IoC и в ФП-языках в виде Reader. Что может предложить мне Go? Инверсия не нужна?


                                        1. divan0 Автор
                                          06.09.2017 19:39

                                          Что может предложить мне Go?

                                          D в SOLID в Go как раз делается с помощью интерфейсов. Я не пойму, вы даже не пытались узнать, как это делается в Go прежде чем комментировать или просто не поняли?


                                          Инверсия не нужна?

                                          Опять бинарная логика. Вы в каком классе школы?


                                          1. raveclassic
                                            06.09.2017 20:01
                                            +1

                                            Ясно, а в Go наоборот. Интерфейсы добавляются только тогда, когда нужно абстрагировать поведение, но не раньше.

                                            Ну и что, что интерфейсы? Вам при каждом вызове функции нужно руками собирать все ее зависимости. Или принимать их в аргументах, а при вызове вызывающей провайдить в нее еще и зависимости функций, которые она вызывает. Потрясающе! Дженериков и частичного применения нет, значит Reader не катит. Классов нет, значит constructor injection не катит.


                                            Вы в каком классе школы?

                                            Аргументы кончились?


              1. 0xd34df00d
                06.09.2017 21:03

                Если вы работаете с GPS координатами, то вы не хотите делать алгоритм, который будет работать с любыми типами — это просто ни к чему.

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


                Кстати, хаскелевские тайпклассы чем-то весьма похожи на гошные interfaces. Только существенно мощнее. Что до рантайм-дженериков — я сам не фанат.


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

                Да. Выбрать алгоритм под структуру данных. Никто не запрещает при этом этому алгоритму быть обобщённым.


                В плюсах я вполне себе писал алгоритм, который работал что со sparse, что с dense-матрицами, делегируя детали реализации этим самым матрицам.


                1. divan0 Автор
                  06.09.2017 21:09

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

                  Представить можно всё. Обобщать надо по мере необходимости, а не "потому что могу". Плохая абстракция это хуже, чем дублирование кода, если уж на то пошло.


                  Кстати, хаскелевские тайпклассы чем-то весьма похожи на гошные interfaces. Только существенно мощнее.

                  Я в курсе, сам давно хочу выучить Хаскелль, но все мои друзья-хаскеллисты признаются, что у них ушло года 3-4 чтобы вообще выйти на какой-то минимально не стыдный уровень. И это таки решающий фактор. Они когда переходят на новые работы, на старой быстренько их хаскель-код переписывают с нуля на чём-то понятном.


                  Никто не запрещает при этом этому алгоритму быть обобщённым.

                  Но и не заставляет. Обобщение не такое уж бесплатное, чтобы "не запрещает" было достаточно.


                  1. 0xd34df00d
                    06.09.2017 21:22

                    Обобщать надо по мере необходимости, а не «потому что могу».

                    Есть и обратное мнение. Сформулировав требования через трейт/тайпкласс/интерфейс, проще убедиться, что ты пишешь не ерунду на частных случаях.


                    Плохая абстракция это хуже, чем дублирование кода, если уж на то пошло.

                    Из этого не следует, что любая абстракция плохая.


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

                    Ну, оно того стоит. Я тоже не за пару месяцев научился что-то адекватное писать, но разница в производительности и корректности/поддерживаемости многократно окупила время на обучение.


                    Но и не заставляет. Обобщение не такое уж бесплатное, чтобы «не запрещает» было достаточно.

                    Ну ещё бы, если по 10 наносекунд на каст надо тратить, как в примере выше с операцией сравнения. Я за компил-тайм-мономорфизацию.


                    1. divan0 Автор
                      06.09.2017 21:29

                      Есть и обратное мнение.

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


                      Из этого не следует, что любая абстракция плохая.

                      А из этого не следует, что любая абстракция хорошая.


                      Ну, оно того стоит. Я тоже не за пару месяцев научился что-то адекватное писать, но разница в производительности и корректности/поддерживаемости многократно окупила время на обучение.

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


                      Ну ещё бы, если по 10 наносекунд на каст надо тратить, как в примере выше с операцией сравнения. Я за компил-тайм-мономорфизацию.

                      Если вы в реальном проекте упретёсь в лоад, когда нужно будет экономить 10 нс, то ничего вам не помешает использовать реализацию binary tree для конкретного типа (с кодогенерацией, или написанной ручками). И не надо рассказывать, что вы во всех проектах используете бинарное дерево для 20+ разных типов, это почти всегда конкретный тип данных.


                      1. 0xd34df00d
                        06.09.2017 21:36

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

                        А я знаю программистов, которые сразу хардкодили все типы и заодно константы.


                        Опен-сорс проекты нормально не поднимешь — 11 с половиной контрибьюторов это мало.

                        Я не знаю, чего б такого опенсорсного написать на хаскеле :( Да и для других языков особо идей нет.


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

                        А вы точно со мной спорите?


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

                        Я в реальных проектах в лоад упираюсь практически всегда, но не суть.


                        Я могу взять вашу реализацию binary tree (или произвольную библиотеку с контейнером) и одним-двумя движениями скодогенерировать реализацию для моего конкретного типа?


                        И не надо рассказывать, что вы во всех проектах используете бинарное дерево для 20+ разных типов, это почти всегда конкретный тип данных.

                        Я почти во всех проектах использую уже единожды написанные std::map/std::unordered_map/boost::multi_index/Data.HashMap/etc.


                        1. divan0 Автор
                          06.09.2017 21:40

                          которые сразу хардкодили все типы

                          Программисты писали типы? Ужас какой, надо же было сразу шаблонами и монадками, а то слишком примитивно. Прям ручками писали типы? Брр..


                          Я могу взять вашу реализацию binary tree (или произвольную библиотеку с контейнером) и одним-двумя движениями скодогенерировать реализацию для моего конкретного типа?

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


                          Я почти во всех проектах использую уже единожды написанные std::map/std::unordered_map/boost::multi_index/Data.HashMap/etc.

                          Вы не поняли. Сколько различных типов вы засовываете в бинарное дерево в типичной программе? 1,2,10,100?


                          1. 0xd34df00d
                            06.09.2017 22:27

                            Программисты писали типы? Ужас какой, надо же было сразу шаблонами и монадками, а то слишком примитивно. Прям ручками писали типы? Брр..

                            Вы как-то слишком сильно иронизируете.


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

                            Пример чего? Я уже потерял нить немножко.


                            Вы не поняли. Сколько различных типов вы засовываете в бинарное дерево в типичной программе? 1,2,10,100?

                            В ближайшем проекте — 11 уникальных троек (тип ассоциативного массива, ключ, значение). Он ещё не сильно большой.


                            1. divan0 Автор
                              06.09.2017 22:45

                              11 уникальных троек (тип ассоциативного массива, ключ, значение)

                              Вы 11 различных типов засовываете в бинарное дерево? А что это вы такое пишете, если не секрет. Правда интересно, что за usecase?


                              1. 0xd34df00d
                                06.09.2017 23:41

                                Обработку потока текстов, если вкратце.


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


            1. Comdiv
              06.09.2017 11:18
              +1

              Потому что мне в моей практике массивы из нескольких элементов встречались не раз и не два.

              А сколько? Сколько строчек кода Вы сэкономите в своём текущем проекте, если в нём будет задействован generic линейный поиск?

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


              1. 0xd34df00d
                06.09.2017 21:17

                Сколько строчек кода Вы сэкономите в своём текущем проекте, если в нём будет задействован generic линейный поиск?

                Не знаю, он там уже и так задействован. Но у меня есть просто куча других мест, где задействованы generic-свертки, map, traverse, sequence и прочие друзья.


                1. Comdiv
                  07.09.2017 01:09

                  Не знаю, он там уже и так задействован.
                  Значит, инвертируйте вопрос. Сколько избыточных строк кода будет, если написать свой линейный поиск?
                  // вариант линейного поиска для тех, кто любит экономить строки
                  for (i = 0; i < len && a[i] != b; i += 1);
                  


                  Но у меня есть просто куча других мест, где задействованы...
                  Можно глянуть?


                  1. 0xd34df00d
                    07.09.2017 02:02
                    +1

                    Значит, инвертируйте вопрос. Сколько избыточных строк кода будет, если написать свой линейный поиск?

                    С десяток-другой, вероятно. Ну, правда, потребуется написать что-то вроде такого


                    lookup _ [] = Nothing
                    lookup e ((k, v):xs) | k == e = Just v
                                         | otherwise = lookup e xs

                    но не суть.


                    Но зачем это писать, если можно сэкономить немного когнитивной нагрузки и не писать?


                    Можно глянуть?

                    К сожалению, мои рабочие проекты не в паблике.


                    1. Comdiv
                      07.09.2017 13:41

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


                      1. 0xd34df00d
                        07.09.2017 20:24

                        В Си или Go линейный поиск считывается моментально

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


                        То есть, конечно, если у вас такой паттерн кода возникает в 10-20 местах, то да, вы к нему привыкните и будете воспринимать со временем как единый цельный глагол, но утверждать, что каждый раз копипастить цикл проще, чем писать слово из нескольких букв — это, ну, перебор как-то.


                        Те, кому по душе сложные языки с этим не согласятся, но и обратный подход они-то могу понять?

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


                        1. Comdiv
                          07.09.2017 23:20
                          +1

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


                          1. 0xd34df00d
                            07.09.2017 23:49

                            Я же говорю по своему опыту, а не из абстрактных соображений.

                            Так и я тоже. В то, что распарсить строку выше и понять, что она делает, занимает у вас столько же времени и ресурсов, сколько распарсить строку lookup a bs, мне верится очень с трудом.


                            Пожалуйста, конкретней, и почему в 1-у строку?

                            Ну, есть массив пар. Пусть даже заранее известного размера. Дан первый элемент пары. Надо найти второй элемент пары, первый элемент которой равен данному элементу, либо как-то грамотно (идиоматично на вами выбранном языке) обработать его отсутствие. Как вы это будете делать?


                            Вы простые команды в терминале копируете или сами пишете?

                            Так этот цикл — это не простая команда, это ближе к шелловским заклинаниям.


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

                            Я и говорю о множестве всех частных случаев в виде линейного поиска.


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

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


                            1. Comdiv
                              08.09.2017 00:53

                              столько же времени и ресурсов, сколько распарсить строку lookup a bs, мне верится очень с трудом.
                              Конечно не столько же — чтобы достоверно узнать, что делает lookup a bs, нужно будет искать реализацию lookup.

                              Надо найти второй элемент пары, первый элемент которой равен данному элементу

                              Что-то вроде этого?
                              for (i = 0; i < len && a[i].key != key; i += 1);
                              if (i < len) {
                                found(a[i].value);
                              } else {
                                not_found();
                              }
                              

                              Обязательно нужно это влепить в 1-у строку? Я-то и цикл написал в 1-у строку для примера любителям считать строки, а не потому, что я так пишу.


                              1. 0xd34df00d
                                08.09.2017 01:03

                                Конечно не столько же — чтобы достоверно узнать, что делает lookup a bs, нужно будет искать реализацию lookup.

                                А чего вы тогда реализацию printf не ищете или не пишете свою, а спокойно (я надеюсь) вызываете библиотечную?


                                Обязательно нужно это влепить в 1-у строку? Я-то и цикл написал в 1-у строку для примера любителям считать строки, а не потому, что я так пишу.

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


                                1. Comdiv
                                  08.09.2017 01:08

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


                                  1. 0xd34df00d
                                    08.09.2017 01:17

                                    На хаскеле? Сохраняя вашу нотацию,


                                    res = lookup key a

                                    Нужно кастомное сравнение cmp?


                                    res = find (cmp key . fst) a

                                    На плюсах?


                                    auto pos = std::find_if(a.begin(), a.end(), [&key] (const auto& pair) { return pair.key == key; });
                                    if (pos == a.end())
                                        notFound();
                                    else
                                        found(pos->second);

                                    и меня это дико бесит.


                                    Жаль, про printf вы не написали.


                                    1. Comdiv
                                      08.09.2017 01:22

                                      На хаскеле? Сохраняя вашу нотацию,

                                      Где обработка найденного и не найденного? Почему разные функции?
                                      На плюсах?
                                      Круто, ничего не скажешь


                                      1. 0xd34df00d
                                        08.09.2017 01:37

                                        Где обработка найденного и не найденного?

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


                                        lookup key a >>= doSmthWithResult

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


                                        myFunc = do
                                            res1 <- lookup key1 a
                                            res2 <- lookup key2 a
                                            doSmthWithResults res1 res2

                                        Или если у вас есть несколько ключей-кандидатов, и вы хотите попробовать их все и вернуть первый найденный:


                                        msum [lookup key1 a, lookup key2 a, lookup key3 a]
                                        -- Или, чтобы меньше писанины,
                                        -- или если список ключей приходит снаружи
                                        msum [lookup k a | k <- [key1, key2, key3]]

                                        С find аналогично.


                                        msum, do и прочие, причём, не завязаны на конкретно возвращаемый тип lookup/find, аналогичные идиомы применимы и для кучи других типов данных в куче других контекстов. Иногда можно просто писать код, выключив мозг, комбинируя всякие msum/traverse/sequence так, чтобы код тайпчекался, а он потом, что очень приятно, работает как и ожидалось. Потому что примитивы разумные.


                                        Почему разные функции?

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


                                        Круто, ничего не скажешь

                                        Увы. Зато можно этот самый lookup написать единожды, работающий с достаточно произвольным типом массива и достаточно произвольными ключами.


                                        1. Comdiv
                                          08.09.2017 01:45

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


                                          1. 0xd34df00d
                                            08.09.2017 02:34

                                            Например, функция doSmthWithResult может выглядеть как-то так:


                                            doSmthWithResult (Just val) = ...
                                            doSmthWithResult Nothing = ...

                                            Или вызывающий код может воспользоваться готовым fromMaybe:


                                            fromMaybe defValue res

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


                                            1. Comdiv
                                              08.09.2017 11:44

                                              Как видно, в полном виде всё выглядит несколько иначе, чем «не сомнительное удовольствие», учитывая также, что в зависимости от типа поиска придётся менять слова, которые не включают в себя полной семантики, поэтому о ней нужно дополнительно помнить.

                                              lookup key a >>= doSmthWithResult
                                              doSmthWithResult (Just val) = ...
                                              doSmthWithResult Nothing = ...

                                              for (i = 0; i < len && a[i].key != key; i += 1);
                                              if (i < len) found(a[i].value);
                                              else not_found();

                                              Все люди разные, и я-то и не спорю, что кому-то первый вариант прийдётся по душе. Но почему же такие люди, не понимают того же самого, что и 2-й вариант другим людям понятней? Не гордыня ли это от ощущения причастности к «истинному» пути?


                                1. divan0 Автор
                                  08.09.2017 01:10

                                  А чего вы тогда реализацию printf не ищете или не пишете свою, а спокойно (я надеюсь) вызываете библиотечную?

                                  В Go есть негласное соглашение — в stdlib и в языке только то, что работает быстро. Дорогие операции нужно делать явно. Многие новички на это ругаются, но это очень круто.


                                1. Comdiv
                                  08.09.2017 01:16

                                  А чего вы тогда реализацию printf не ищете или не пишете свою
                                  1. Так уж получилось, что printf использую только для примеров, в обычном коде — нет. Знали бы Вы, сколько глюков на ней висит.
                                  2. Чем объёмней и сложней код, тем меньше его пишут врукопашную, но когда нужно специальное поведение, то пишется своё, да. Без этого никуда


                                  1. 0xd34df00d
                                    08.09.2017 01:18

                                    А, ну последовательный подход. Ясно, спасибо.


                                    1. Comdiv
                                      08.09.2017 01:31

                                      Пожалуйста. Это вообще беда Си, из стандартной библиотеки половиной лучше не пользоваться. Наследие диких времён. Но можно и поиронизировать, да.


                            1. Comdiv
                              08.09.2017 01:06

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


                              1. 0xd34df00d
                                08.09.2017 01:19

                                Нет, сделаю на бумажке ручкой, а скорее, так как напрочь забыл этот раздел математики, в Wolfram Alpha.


                                1. Comdiv
                                  08.09.2017 01:27

                                  В общем случае у сходящегося ряда нет красивой формулы. Я имел ввиду численный метод


                                  1. 0xd34df00d
                                    08.09.2017 01:39

                                    Вычматы — мой самый ненавидимый предмет в вузе пополам с урматами :)


                    1. divan0 Автор
                      07.09.2017 17:04

                      Но зачем это писать, если можно сэкономить немного когнитивной нагрузки и не писать?

                      Я понял, что многие понимают термин "когнитивная нагрузка" ровно наоборот. Когнитивная нагрузка — это то, что вы должны выучить и заучить и держать в голове, чтобы понимать код. Вы же этим термином называете количество кода, которое нужно читать, но это вот ровно наоборот.


                      1. 0xd34df00d
                        07.09.2017 20:27

                        Вам правда нужно что-то учить, чтобы понять, что lookup означает поиск в списке пар, а какой-нибудь std::set_intersection — пересечение двух упорядоченных последовательностей?


                        Как и обещалось выше: может, это просто говорит об уровне проектов, типично реализуемых на Go, и программистов на нём?


          1. vintage
            06.09.2017 09:34

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

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


            1. Comdiv
              06.09.2017 11:21

              Пока не воплощена на практике идея суперкомпиляции Валентина Турчина, это утверждение остаётся благим пожеланием.


              1. 0xd34df00d
                06.09.2017 21:15

                Плюсы со специализацией с этим как-то справляются.
                Хаскель с возможностью задавать дефолт-реализации методов тайпклассов тоже как-то справляется.


                1. Comdiv
                  06.09.2017 22:44

                  Под справляются Вы имеете ввиду, что такое

                  [1, 2, 3, 4 ,5].contains(n)

                  автоматически превращается в такое?
                  0 != ((1 << n) & 62)


                  Мой скромный опыт показывает, что ассоциативный массив на template С++ не справляется с наколенным воплощением на Си


                  1. 0xd34df00d
                    06.09.2017 23:46

                    Нет, в такое не превращается. Но вот в SSE-enabled-поиск вполне может превратиться. К сожалению, конкретный код сейчас не приведу.


                    А по ссылке — ну, человек, делающий мапу с ключом в const char*, несомненно знающий. Исходников С-версии у вас не сохранилось случаем, кстати? Мне бы хотелось потестить.


                    1. Comdiv
                      07.09.2017 00:07

                      Исходников С-версии у вас не сохранилось случаем, кстати?
                      В статье была ссылка на github, иначе в чём смысл разглагольствований?


                      1. 0xd34df00d
                        07.09.2017 00:32

                        Умудрился пропустить, спасибо! Вечером сегодня-завтра поиграюсь.


                      1. 0xd34df00d
                        07.09.2017 02:10
                        +1

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


                        Ваш вариант с 1000 итерациями на некоторых (не ваших) тестовых данных — 1.177 секунд. Мой вариант со стандартным хешем — 1.6 секунд. Медленно, да. Поменял на ваш хеш — стало среднее 1.185 секунд. Разница статистически незначима. Такие дела.


                        сам вариант
                        #include <unordered_map>
                        #include <fstream>
                        #include <iostream>
                        #include <string>
                        #include <vector>
                        
                        const auto Size = 1023;
                        
                        struct CharsHash
                        {
                            size_t operator()(const std::string& str) const
                            {
                                int i, h;
                                i = 1;
                                h = str[0];
                                while ((i < 3) && (str[i] != '\0'))
                                {
                                    h = (h * 256 + (unsigned char)str[i]) % Size;
                                    i++;
                                }
                                return h;
                            }
                        };
                        
                        auto loadKeywords(const std::string& path)
                        {
                            std::unordered_map<std::string, int, CharsHash> result;
                            result.reserve(Size);
                            std::ifstream istr { path };
                            std::string str;
                            int idx = 0;
                            while (istr >> str)
                                result[str] = idx++;
                            return result;
                        }
                        
                        auto loadWords(const std::string& path, size_t maxSize)
                        {
                            std::vector<std::string> result;
                            size_t totalSize = 0;
                            std::ifstream istr { path };
                            std::string str;
                            while (istr >> str)
                            {
                                totalSize += str.size() + 1;
                                result.push_back(std::move(str));
                                if (totalSize > maxSize)
                                    break;
                            }
                            return result;
                        }
                        
                        int main(int argc, char const *argv[])
                        {
                            const auto& kws = loadKeywords("data/keywords.data");
                            const auto& words = loadWords("data/words.data", 512 * 1024);
                        
                            const auto count = std::stoi(argv[1]);
                            int sum = 0;
                            for (int i = 0; i < count; ++i)
                                for (const auto& word : words)
                                {
                                    const auto pos = kws.find(word);
                                    sum += pos == kws.end() ? -1 : pos->second;
                                }
                            std::cout << sum << std::endl;
                        }


                        1. Comdiv
                          07.09.2017 13:59

                          Здорово, что Вы написали свою программу, но сравнив её с тестом, я очень легко нашёл недостающий компонент:
                          result.reserve(1023);
                          Получается, что С++ hash array приближается к скорости C кода только если воспользуется знаниями, которыми обладает разработчик, который может написать hash array самостоятельно — hash функцией и нужными значением резерва. Когда я попытался применить reserve(1023) в тесте, естественно, получил отлуп — map, сделанная через деревья, не имеет такого метода. Единого интерфейса тоже нет.

                          Также у меня Си код всё равно выполняется быстрей на статистически различимую величину. А С++ hash array в test проекте c reserve() выполняется быстрей на статистически различимую величину, чем представленная Вами программа, полностью написанная на C++.

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


                          1. 0xd34df00d
                            07.09.2017 20:37

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

                            Да, 1023 я взял, кстати, из вашего кода.


                            Получается, что С++ hash array приближается к скорости C кода только если воспользуется знаниями, которыми обладает разработчик, который может написать hash array самостоятельно — hash функцией и нужными значением резерва.

                            А какой тезис вы выдвигаете?


                            Что на С++ с его ООП невозможно написать так же эффективно, как на С? Это не так. И даже не надо для этого пользоваться подмножеством С — у меня в коде вполне себе каноничные плюсы.


                            Что для эффективного решения задачи надо знать детали реализации? Конечно. Если вы наперёд знаете, сколько у вас примерно будет элементов, то имеет смысл сделать reserve, чтобы в бакетах было поменьше коллизий. 1023 — это всё-таки сильно больше 45 — числа элементов, которые там действительно лежат. Если вы знаете, какой хеш для вас подойдёт лучше — имеет смысл им воспользоваться. В случаев плюсов и ООП (но тут на самом деле не ООП, а policy-based design по Александреску, но какая разница) вам нужно просто передать другой хешер, и всё. Почему хешер по умолчанию работает хуже — хрен его знает, надо смотреть.


                            Можете, кстати, вместо reserve играться с load factor'ом. Когда я в своём коде его выставляю в 0.1, то получаю те же 1.183-1.187 секунд. Выставляю в 0.2 — 1.220. Выставляю в 0.5 — 1.480.


                            Когда я попытался применить reserve(1023) в тесте, естественно, получил отлуп — map, сделанная через деревья, не имеет такого метода. Единого интерфейса тоже нет.

                            Он есть, когда это имеет смысл. reserve для дерева не имеет большого смысла в силу ряда причин.


                            Также у меня Си код всё равно выполняется быстрей на статистически различимую величину.

                            С моим вариантом, с кастомным хешем и reserve? Ради любопытства, а насколько?


                            А С++ hash array в test проекте c reserve() выполняется быстрей на статистически различимую величину, чем представленная Вами программа, полностью написанная на C++.

                            То есть, плюсы быстрее? Ну так тем лучше!


                            1. Comdiv
                              08.09.2017 00:33

                              А какой тезис вы выдвигаете?
                              Это означает, что для того, чтобы написать вариант на С++, приближающийся снизу по скорости, надо знать всё то же, что и на Си, плюс нюансы библиотеки С++. Выгоды, на мой взгляд, нет исходя из контекста нашего разговора.

                              С моим вариантом, с кастомным хешем и reserve? Ради любопытства, а насколько?
                              Как выяснилось, очень зависит от сочетания компилятора и процессора. На рабочем ноутбуке на c gcc 10%, на домашнем, на котором всё новее — 5%. А на clang Си наоборот, сильно отстаёт.


                              1. 0xd34df00d
                                08.09.2017 00:43

                                Это означает, что для того, чтобы написать вариант на С++, приближающийся снизу по скорости,

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


                                надо знать всё то же, что и на Си

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


                                плюс нюансы библиотеки С++

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


                                Выгоды, на мой взгляд, нет исходя из контекста нашего разговора.

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


                                Как выяснилось, очень зависит от сочетания компилятора и процессора. На рабочем ноутбуке на c gcc 10%, на домашнем, на котором всё новее — 5%. А на clang Си наоборот, сильно отстаёт.

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


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


                                1. Comdiv
                                  08.09.2017 01:00

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


                                  1. 0xd34df00d
                                    08.09.2017 01:05

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

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


                                    Хотя, конечно, если вся программа состоит из подсчёта количества слов на входе, то это не имеет смысла.


                                    В том и прелесть, что я делаю только то, что нужно.

                                    Если ваша цель — написать под данный конкретный случай, то да, конечно.


      1. MikailBag
        06.09.2017 17:47
        +1

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


  1. lega
    05.09.2017 13:17
    +1

    Проблемма не в node или js, дело в асинхронном коде (походе) этой платформы. На python асинхронный код тоже не прост как синдронный.

    Из года в год вижу как видные разрабочтики приходят к пониманю повышенной сложности асихронного кода, например тут неплохо описано Javascript: фрактал отсоса by PerlPower
    Так же bobuk высказался «программировать асинхронный код сложно».

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


    1. vintage
      05.09.2017 14:08
      +5

      Скажу жёстче — достаточно иметь голову, а не вестись на хайп.


    1. nile1
      05.09.2017 14:48

      Отдельные асинхронные блоки не так плохи. Ужасно то, что асинхронные функции можно вызывать только из асинхронных функций, и в итоге весь код в них. На эту тему есть отличная статья: What color is your function?


    1. Nakosika
      06.09.2017 18:30

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


      1. 0xd34df00d
        06.09.2017 21:18

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


        1. Nakosika
          07.09.2017 00:46

          Полностью согласен. Вот бы в кложур добавить типы и выкинуть скобки…


  1. debounce
    06.09.2017 18:36

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