image

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

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

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

Вот семь из устрашающих уголков мира программирования, на которых легко можно написать: «Здесь живут драконы».

Многопоточность


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

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

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

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

Замыкания


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

Решение — «замыкание» — является одной из самых больших причин головной боли для программистов JavaScript (а теперь и Java и Swift). Новички и даже многие опытные программисты не могут понять, что замыкается и где могли бы быть границы этого так называемого замыкания.

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

Слишком большие данные


Когда ОЗУ начинает переполняться, всё падает. Не имеет значения, выполняете вы навороченный статистический анализ потребительских данных или работаете с привычной старой электронной таблицей. Когда машина выходит за пределы ОЗУ, то она обращается к т.н. виртуальной памяти, которая действует на чрезвычайно медленном (по сравнению с ОЗУ) жёстком диске или твердотельном накопителе. Это, конечно, лучше, чем полная остановка или завершение задания, но работа замедляется в любом случае.

Проблема в том, что быстродействие жёстких дисков в 20-30 раз меньше, чем у ОЗУ, а накопители, массово продаваемые на рынке, работают ещё медленнее. Если какой-то другой процесс также пытается в это время писать на диск или считывать с него, то ситуация становится просто драматической, поскольку эти накопители могут выполнять только одну задачу в каждый момент времени.

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

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

NP-полная задача


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

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

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

Существование таких довольно хороших решений делает «драконов» только более загадочными. Никто заранее не может быть уверен, действительно ли трудны эти проблемы или же они могут быть сравнительно легко решены — если вас устроит ответ, который будет просто хорошим.

Безопасность


«Есть познанное знание — то, о чём мы знаем, что знаем», — сказал однажды на пресс-конференции Дональд Рамсфельд, министр обороны второй администрации президента США Джорджа Буша. «Есть также познанное незнание — то, о чём мы знаем, что не знаем. Но есть ещё и непознанное незнание — это то, о чём мы не знаем, что не знаем.»

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

Возможность подобного проникновения можно теперь не рассматривать как «непознанную», но ведь могут существовать и другие? Мы не имеем ни малейшего понятия, возможно ли заделать дыры, если мы даже не знаем, существуют ли они. Можно тщательно защитить пароли, но существуют способы взлома, которые мы не можем даже представить себе. Работа с компьютерной безопасностью доставляет, несомненно, море удовольствия. А когда речь идёт о программировании, то мышление, ориентированное на безопасность, становится всё более важным. Нельзя перекладывать на профессионалов, занимающихся безопасностью, расчистку созданной вами путаницы.

Шифрование


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

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

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

Управление идентификацией


Многие любят рисунок, опубликованный в газете «The New Yorker» в 1993 году, с надписью: «В интернете никто не знает, что ты собака». Он даже имеет свою собственную страницу в Википедии с четырьмя детально проработанными разделами. (В интернете мало кто знает старую шутку об анализе юмора и препарировании лягушек.)

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

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

Немногое из этого имеет значение для мира пустословия в Snapchat или Reddit, но множество взломанных страниц Facebook немного обескураживает. Нет какого-то лёгкого способа заниматься в сети серьёзными вопросами, такими как собственность, деньги, здравоохранение и в значительной степени всё остальное в жизни, кроме «светского» разговора на общие темы.

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

Надёжность измерения


Конечно, когда речь идёт о программировании, то встаёт вопрос — есть ли хотя бы способ, с помощью которого мы можем измерить сложность проблемы? Никто, на самом деле, не знает этого. Мы знаем, что некоторые проблемы решить легко, но совсем другое дело определить, насколько трудно это сделать. NP-полнота является лишь одной частью сложной попытки кодифицировать сложность алгоритмов и анализа данных. Теория полезна, но она не может предложить никаких гарантий. Заманчиво сказать, что трудно даже знать, трудна ли проблема, но это, конечно, шутка.
Поделиться с друзьями
-->

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


  1. FirsofMaxim
    27.11.2016 20:34
    -1

    В Swift для замыканий ввели типы аргументов — weak/unowned, внутри при доступе к вызываемому контексту требуется написать self, тем самым среда как бы говорит — «ага! self написал — утечку осознал!» (здесь я имею ввиду что если в замыкании используется self без типа аргумента weak/unowned — привет утечка)


    1. storoj
      27.11.2016 21:53
      +4

      ничего и не утечка


      1. FirsofMaxim
        27.11.2016 22:05
        -2

        а вот и утечка если:
        1) замыкание
        2) внутри self
        3) self не указан как weak/unowned
        Немного хелпа тут

        self связывается как strong ссылка если не указано иное.


        1. storoj
          27.11.2016 22:22
          +1

          dispatch_async({ print(self) }) – тоже утечка?


          1. FirsofMaxim
            28.11.2016 06:35
            -3

            Если ссылка на очередь нигде не сохраняется, то конечно утечки нет, но все меняется если пробовать вызвать код в main очереди, например (Swift3):

            Запустите в Playground этот код:

            class A {
                init(){
                    print("A init")
                }
                
                deinit {
                    print("A deinit")
                }
                
                public func fooBar(){
                    print("A.fooBar")
                }
                
                public func fooBarAsync(){
                    print("A.fooBarAsync")
                    DispatchQueue.main.async {
                        self.fooBar()
                    }
                    
                }
            }
            
            
            func testCase(){
                let a = A()
                a.fooBar()
                a.fooBarAsync()
            }
            
            
            testCase()
            

            ##########
            A init
            A.fooBar
            A.fooBarAsync
            Ухты! Где deinit растак его?!

            Делаем так:
            public func fooBarAsync(){
                    print("A.fooBarAsync")
                    DispatchQueue.main.async { [ unowned self] in 
                        self.fooBar()
                    }
                    
                }
            

            ##########
            A init
            A.fooBar
            A.fooBarAsync
            A deinit
            Оуе детка! Я тебя вижу :)


            1. storoj
              28.11.2016 15:31
              +2

              Рекомендую добавить это в начало:
              import PlaygroundSupport
              PlaygroundPage.current.needsIndefiniteExecution = true


              А в последнем примере по коду разве не должен был быть ещё один A.foobar после deinit? Может быть его нет потому что всё благополучно упало?


              1. FirsofMaxim
                28.11.2016 19:30

                Все работает без падений, попробуйте.


  1. VovanZ
    27.11.2016 20:45
    +56

    Не нашёл в списке инвалидации кэша и придумывания названий для вещей. Разочарован.


    1. Envek
      27.11.2016 21:49
      +36

      А ещё Unicode и работы с временем. Вот где драконы роятся!


      1. neit_kas
        28.11.2016 00:07

        Unicode обобщил бы на кодировки в целом.


        1. DistortNeo
          28.11.2016 03:26
          +3

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


          1. neit_kas
            28.11.2016 06:41
            +2

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


            1. grossws
              29.11.2016 16:00

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


              1. neit_kas
                01.12.2016 23:38

                У меня notepad-qq опознаёт её как iso8859-1. При этом notepad++ опознавал по-другому: какая-то очень похожая на 1251, отличия были буквально в паре букв. Точно помню 'й' и вроде 'я' страдали.


                1. grossws
                  02.12.2016 00:34
                  +1

                  Как раз в mac cyrillic есть эта проблема. Например 0xff там ¤, а не я, вместо Э -> Ё, Ю -> ё, Я -> я и т. п. Ну и остальные заглавные должны страдать.


          1. vikarti
            28.11.2016 15:29

            Причем даже крупные компании — не всегда корректно это обрабатывают.
            Пример: скопируем из ЛК мегафона какую то сумму со знаком рубля (новым) в буфер обмена а потом попробуем ее вставить в создаваемый там же тикет поддержки. Она вставится. Только вот при попытке отправить будет сообщение что ошибка (без указания деталей). если заменить символ на просто Р — все отправляется.


            1. DistortNeo
              28.11.2016 15:42

              Мне встречался случай, когда я не мог отправить сообщение (не помню куда), содержащее в теле слово «select» — вот такая доморощенная защита от sql injection.


              1. 0x9d8e
                28.11.2016 18:10

                Вконтакте в 2008-2009 такое творил. Точнее просто вырезал всё, что ему казалось похожим на SQL.


    1. neit_kas
      28.11.2016 00:11
      +2

      Ещё добавил бы:
      3 угла треугольника: скорость выполнения, затрачиваемая память и поддерживаемость кода (поиск золотой середины).
      Архитектура ПО: когда заранее не в курсе, куда занесёт и, следовательно, какую архитектуру построить.


    1. ababo
      28.11.2016 11:12

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


      1. Pakos
        01.12.2016 10:12

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


  1. Labunsky
    27.11.2016 21:49
    +2

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

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


    1. a1111exe
      28.11.2016 00:22
      -3

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

      Ой ли? А если реинкарнация злодея Гитлера и гения Канта в одном лице, усугублённая современным высшим образованием и отсутствием внятных моральных ориентиров?


      1. poxu
        28.11.2016 12:01
        +2

        А если реинкарнация злодея Гитлера и гения Канта в одном лице

        Хотел написать какую-нибудь ядовитую шутку про то, что ничего гениального Канта не сделал, но передумал. Лучше спрошу вопрос.


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


        И что может сделать гений, если он даже толком коллегу подсидеть зачастую не способен?


        1. raacer
          28.11.2016 15:03

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


          1. poxu
            28.11.2016 17:42

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


            1. Alexeyslav
              28.11.2016 17:45

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


              1. poxu
                28.11.2016 18:48

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


            1. raacer
              28.11.2016 18:14

              Речь шла об «Если бы вы нашли способ подслушивать каждый разговор» же?..


              1. poxu
                28.11.2016 18:48

                А потом вы перевели разговор на ядерный реактор :)


        1. a1111exe
          01.12.2016 22:29

          Было написано «один человек в масштабах планеты особой угрозы не несёт». Мой тезис: технически возможно одному человеку угрожать благополучию всего мира. И я привёл пример, в котором человек наделён властью (Гитлер был наделён властью), умён и аморален. Такое невозможно? Серьёзно?

          P.S. Позвольте спросить, чем Вам не угодил Кант?


    1. Nordicx86
      28.11.2016 10:26
      -1

      как вам сказать «коды» пуска ядерных ракет — в курсе ТОЧНО группа лиц,, но они хранятся вполне и вполне надежно.
      тут ТОЖЕ САМОЕ — реально методы взлома существуют(«непознаное незнаю»), но их вам ни кто не озвучит пока вы сами не попадете в условия когда сохранение тайны станет вашим непосредственным, я бы даже добавил ЖИЗНЕННО важным интересом… ДУМАЙТЕ…


      1. Alexeyslav
        28.11.2016 11:21

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


    1. vikarti
      28.11.2016 15:44

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

      А если никому не сообщил но выложил в багтрекер мозиллы сертификат для mozilla.org, подписанный SubCA с CN='Klingon Empire', в свою очередь подписанный VeriSign + тоже самое но в качестве RootCA — использован допустим CNNIC и с комментарием что никто VeriSign/CNNIC не взламывал, просто современные протоколы ЭЦП — ненадежны… без указания деталей. Это вообще — угроза или предупреждение об уязвимости?


  1. Vjatcheslav3345
    27.11.2016 22:14
    +8

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

    Кажется я теперь знаю, как понятно объяснять своей девушке проблему замыканий: "Знаешь, начнём с того, что это чем то похоже на наиновейшие теории пространства-времени, которые мы с таким удовольствием вчера обсуждали в гостях у Маньки-соседки. Давай рассмотрим [беру её за руку] такую простенькую вещь как обыкновенная «червоточина» в пространстве-времени..."


  1. Zonzen
    27.11.2016 22:40
    -3

    Статью следует назвать — «семь самых частых ошибок некомпетентных программистов».


    1. third112
      27.11.2016 22:50
      -3

      Верно. Не понятна адресация. М.б. это попытка популярной статьи для начальников, которые сами программировать не умеют? :)


      1. third112
        28.11.2016 12:27
        -1

        Ура! Статья нашла своего читателя: прибежали некомпетентные минусаторы, которым нечего возразить словами, зато минусы раздали :)) -«Аргументация» на уровне статьи!


      1. aon24
        28.11.2016 13:07
        +3

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


        1. third112
          28.11.2016 13:36
          -1

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


          1. aon24
            28.11.2016 14:19

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


            1. third112
              28.11.2016 14:50

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


              1. aon24
                28.11.2016 16:09
                +1

                Я не случайно написал «наберется опыта и поймет...».
                Я сам по юности лет, получив в Питере хорошее образование и поработав пару лет программистом, был послан в Уфу в качестве гуру поучать местных спецов (интернет только зарождался). Через пару часов общения я понял, что мои башкирские ровесники разбираются в проблеме и в программировании лучше меня :)
                Пришлось самооценку скорректировать.


    1. Alexey_Sarychev
      28.11.2016 00:22
      +9

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

      Незнание одной области не делает программиста некомпетентным.

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


      1. Zonzen
        28.11.2016 08:57

        Незнание одной области не делает программиста некомпетентным.

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


        1. Alexey_Sarychev
          28.11.2016 09:09

          Я как раз написал автору комментария тоже самое — обобщение не верно.

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

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


          1. Zonzen
            28.11.2016 09:18

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

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

            не имеет никакого смысла.


            1. Alexey_Sarychev
              28.11.2016 09:34

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

              Если есть множество «программист», и оно содержит подмножества «системный программист» и «веб программист», то, если объект не является системным программистом, он все еще имеет шанс прибывать в множестве программистов.

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


      1. third112
        28.11.2016 12:47

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


    1. a1111exe
      28.11.2016 00:40
      +9

      Рискую предположить, что намного больше 50% кода в настоящее время пишется программистами, которых Вы бы назвали некомпетентными. И это реальность, которой безразлично, что кому-то из компетентных гуру-программистов она не нравится. Имхо, единственный выход — культивация сообществ наподобие Хабра, где регулярно появляются материалы, призванные тем или иным образом ликвидировать ту или иную некомпетентность. Ибо книги и университеты, увы, не охватывают всё многообразие продакшена.

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


      1. maxpsyhos
        28.11.2016 04:42
        +3

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


        1. a1111exe
          01.12.2016 22:36

          Подпишусь под каждым словом.


      1. Zonzen
        28.11.2016 08:52

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

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


        1. Pakos
          28.11.2016 11:02

          Софта станет на 50% меньше, но станет ли он лучше? Если оставшиеся программисты «размажутся» по направлениям и получится что кто-то попадёт в область своей некомпетентности и снова окажется «плохого софта 50%» и снова надо уходить половину из профессии. Повторить. Или если каждый окажется на прежнем месте, то будет вариант «мы тут сделали, но это бесполезно — наши данные никому не нужны, т.к. их некуда применять».


        1. third112
          28.11.2016 12:59

          ИМХО из того факта, что «софт с каждым годом становится хуже» логически не следует, что программисты стали хуже. Если хорошему программисту дать слишком сжатые сроки — он либо не выполнит задачу, либо схалтурит. Во многом виновата сетка: когда появилась возможность каждодневных автоматических обновлений, многие фирмы решили, что им выгоднее выбрасывать на рынок сырые продукты — главное опередить конкурентов. Мы живем в мире непрочных вещей и сырого софта, культура этого мира — потребительская: «покупайте как можно чаще».


          1. Zonzen
            28.11.2016 18:19
            -1


          1. taujavarob
            28.11.2016 22:03

            Мы живем в мире непрочных вещей и сырого софта, культура этого мира — потребительская: «покупайте как можно чаще».


            Мир спасёт постоянная подписка.

            На всё. На пользование (и обновление, конечно) софта, авто, дома…

            «покупайте как можно чаще»? — Нет, это устарело — «не покупай! — подпишись на сервис, плати и живи.»

            Сервис — это предоставление (когда нужно тебе) софта, авто, дома, еды, отдыха.

            Иначе говоря — "Перестань владеть вещами и программами — подпишись на сервис и живи!" (С)

            P.S. Пример — платная подписка на то, что новый айфон ты получишь взамен старого, как только новая модель айфона начнёт производиться. — "Подпишись и используй, пока жив". (С)


        1. a1111exe
          01.12.2016 22:47

          Все джуниоры тоже? Они по определению некомпетентны.

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

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

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


  1. third112
    27.11.2016 22:47

    ИМХО про многопоточность в принципе верно сказано. Действительно не быстро и не охотно внедряется. Но очень полезная (и зачастую необходимая) вещь, когда грамотно использована. Стоило бы CUDA упомянуть…

    Про «Слишком большие данные» — очевидно. И как-то слишком примитивно. Есть разные способы сжатия данных, в одной статье не перечислить, но хоть сказать, что есть — было бы не вредно.

    Про NP сказано много слишком таинственного, конспирологичного. Тут ИМХО автор пытается сесть между двух стульев: для популярного объяснения слишком непонятно, а для спецов, достаточно простого упоминания, что
    P =? NP пока остается открытой проблемой.


    1. third112
      27.11.2016 22:56

      PS Про «червоточину» в континууме данные-время у меня слов не нашлось :)


    1. Dum_spiro_spero
      28.11.2016 09:27

      Скорее всего это проблема нынешнего обучения программированию. Преподаватели учат тому, чему учили их.
      Надо СРАЗУ со школы учить концепции многопоточности.
      Как сейчас помню — э… «напишите алгоритм мытья окна». А надо так — есть четыре брата — им надо помыть окно, при этом не переругаться и не выбить это окно нафиг. Жизненный опыт подсказывает, что две последние задачи могут оказаться существенно сложнее чем первая.


  1. Scratch
    27.11.2016 22:52
    +2

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


    1. lgorSL
      28.11.2016 00:25

      del


  1. lgorSL
    28.11.2016 00:26

    NP-полная задача

    Существует целая куча задач, которые проблематично вычислить без всякой np-полноты (Особенно если использовать "слишком большие данные"). Автор почему-то их не упомянул.


  1. IIvana
    28.11.2016 03:40
    +3

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


    1. Suvitruf
      28.11.2016 08:38

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


    1. vanxant
      28.11.2016 10:29

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


      1. IIvana
        28.11.2016 14:51

        Ну это имхо условная проблема. Конечно замыкание замыкает все что видит снаружи, даже если оно ему не нужно для работы. И сборщик мусора не почистит. Но во-первых, если замыкание динамически изменяемое, то бывшее ненужное внезапно может оказаться нужным. А во-вторых, если жалко держать большой ненужный объект в памяти, переменную, с ним связанную можно (в тех языках, с которыми я сталкивался) пересетить на ноль или вообще заандефить (отбиндить или как это сказать — в общем удалить связь имя-значение в словаре связей окружения). По-русски говоря — почистить за собой мусор вручную :) Хотя, с натяжкой это наверное можно записать в драконы языков с GC.


    1. Juraseg
      28.11.2016 12:09
      +2

      Проблема с mutability. Пример на Python:

      fns = []
      for i in [1, 2, 3]:
          def inner():
              return i
          fns.append(inner)
      

      На первый взгляд список «fns» должен содержать функции, которые возвращают 1, 2 и 3. Но на самом деле все три функции будут возвращать 3. В Javascript та же печенька. А в Scheme в такую ловушку попасть сложнее, потому что изменение переменное очевидно — с помощью функции set!, и достаточно редко. А в Python или Javscript переменные меняются повсеместно явно и неявно.


      1. raacer
        28.11.2016 15:09
        -1

        Я запустил этот код, и увидел три разных функции и три разных значения, возвращаемых ими. Что я сделал не так?

        >>> fns = []
        >>> for i in [1, 2, 3]:
        ...     def inner():
        ...         return i
        ...     fns.append(inner)
        ... 
        >>> fns
        [<function inner at 0x7fbd340cef50>, <function inner at 0x7fbd340d0050>, <function inner at 0x7fbd340d00c8>]
        


      1. raacer
        28.11.2016 15:12
        -1

        >>> vls = []
        >>> for i in [1, 2, 3]:
        ...     def inner():
        ...         return i
        ...     vls.append(inner())
        ... 
        >>> vls
        [1, 2, 3]
        


        1. alex4321
          29.11.2016 15:08

          А теперь — запусти их отложенно и увидишь [3,3,3]. Вроде бы.
          А чтобы выкрутиться — понадобится что-то типа

          rng=[1,2,3]
          fns=[]
          for i in fns:
            def generator(counter):
              def func():
                return counter
              return func
            fns.append(generator(i))
          


      1. raacer
        28.11.2016 15:19

        То же самое на JS:
        vls = []
        for (var i=1; i<=3; i++) {
            function inner() {
                return i;
            }
            vls.push(inner());
        }
        vls
        [1, 2, 3]
        


      1. raacer
        28.11.2016 15:26

        Даже вот так, чтобы уж совсем не было сомнений, где какая функция и что она возвращает:
        fns = []
        for (var i=1; i<=3; i++) {
            function inner() {
                return i;
            }
            fns.push(inner);
        }
        for (var i=0; i<fns.length; i++) {
            console.log(fns[i]());
        }
        0
        1
        2
        


        1. discopalevo
          28.11.2016 15:54
          +1

          а теперь поменяй во втором цикле i на j, в js область видимости у переменных это функция а не блок.


          1. raacer
            28.11.2016 16:02

            Да, точно! Спасибо. Сам себя запутал :) Я-то думаю, что за магия с параметрами цикла… ))) Ну тогда всё предсказуемо работает, как и должно.

            Тогда непонятно, почему «На первый взгляд список «fns» должен содержать функции, которые возвращают 1, 2 и 3.» Ведь все функции возвращают значение одной и той же переменной. На чей первый взгляд? Непосвященного в принцип работы замыканий — возможно. Ну так надо учить матчасть, что ли…


            1. poxu
              28.11.2016 18:52

              Сколько не учи матчасть — простор для создания ошибок — огромный. А если вместо целого i передавать объект — станет ещё непонятнее.


      1. raacer
        28.11.2016 15:35

        Возможно, Вы хотели продемонстрировать что-то вроде такого?

        JS: Все функции возвращают 3
        fns = []
        var return_value;
        for (var i=1; i<=3; i++) {
            return_value = i;
            function inner() {
                return return_value;
            }
            fns.push(inner);
        }
        for (var i=0; i<fns.length; i++) {
            console.log(fns[i]());
        }
        3
        3
        3
        


  1. Fedcomp
    28.11.2016 09:37

    > Многопоточность
    Неплохо работает в Rust.


  1. Zerthimon
    28.11.2016 11:10
    +1

    off by one?


  1. EvilArcher
    28.11.2016 14:02

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


  1. MrFrizzy
    28.11.2016 14:24

    Имхо не некомпетентность, а специализация :)


  1. potan
    28.11.2016 14:29

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


  1. raacer
    28.11.2016 15:01

    Многопоточность

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

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


    1. DistortNeo
      28.11.2016 15:39
      +1

      Проблема в том, что железо императивно.


      1. raacer
        28.11.2016 15:52

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


    1. maxpsyhos
      29.11.2016 04:36

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


      1. Dark_Daiver
        29.11.2016 09:02

        Ды, никак.
        Идея чистых функций в том, что они не меняют состояние. Нет изменяемого состояния — можно параллелить сколько угодно вызовов функций, они не смогут друг другу «навредить» by design.
        Запись в файл который кто-то читает, это уже изменение состояния. Как это разрулить в рамках ФП я, к сожалению, не знаю =)


  1. sbagan
    28.11.2016 15:46
    +1

    NP-полная задача != NP задача, NP-полная — любую NP задачу можно к ней свести(например задача коммивояжера — NP-полная), определение которое тут написано — просто задача из класса NP, к тому же практической ценности в NP не так много(хотел бы посмотреть как будут масштабировать n^100, это же из P задача:)


  1. grossws
    29.11.2016 15:57

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

    Гнать ссаными тряпками. КГ/АМ, в общем, если выражаться прямо.


    Виртуальная память у него на hdd/ssd. А к оперативке он, видимо, доступ не через MMU получает, а через libastral.