Известно, что на старых картах, на неизведанных территориях, часто помещали зловещее предупреждение: «Здесь живут драконы». Вероятно, смысл этого предупреждения состоял в том, что не стоит входить в это пространство мира, не будучи готовыми сражаться с внушающим ужас противником. Всё что угодно может случиться на этих загадочных просторах, и нередко такое «что угодно» может закончиться очень плохо.
Программисты, возможно, являются несколько более цивилизованными, чем средневековые рыцари — однако это вовсе не означает, что современный технический мир не имеет своих технических драконов, поджидающих нас в непредвиденных местах: сложные проблемы, которые всплывают именно тогда, когда подходит срок сдачи работы или в моменты особенно высоких нагрузок и ответственной работы; конкуренты, которые прочитали руководство и знают, что недостаточно хорошо реализовано; злые «бесы», которые знают, как использовать неустранённые до конца баги и дефекты программ, причём узнают это часто сразу же после того, как программа сдана в использование.
Находятся люди, которые спокойно спят ночью, согреваемые своей наивной уверенностью, что компьютеры совершенно предсказуемы и без устали выдают потоком правильные ответы. Как же мало им ведомо! Несмотря на серьёзнейшие усилия разработчиков чипов, создателей языков и миллионов программистов, есть ещё в программировании опасные чащи, которые могут погубить даже самых продвинутых из программистов и разработчиков.
Вот семь из устрашающих уголков мира программирования, на которых легко можно написать: «Здесь живут драконы».
Многопоточность
Выглядит хорошей идеей. Разбить вашу программу на независимые секции и дать возможность операционной системе обрабатывать их как отдельные небольшие программы. Если процессор имеет четыре, шесть, восемь или больше ядер, то почему бы не написать программу так, чтобы иметь четыре, шесть, восемь или больше потоков, использующих все ядра независимо?
Идея работает — когда все части являются, действительно, полностью раздельными и никак не связаны друг с другом. Но если они должны получать доступ к одним и тем же переменным или записывать биты в одни и те же файлы — игра окончена. Какой-то из потоков выйдет на эти данные первым, и невозможно предсказать какой.
Поэтому мы создаём мониторы-синхронизаторы, семафоры и другие средства для упорядочения мультипоточной путаницы. Когда они работают, то дело идёт. Они просто вводят другой уровень сложности и превращают действие по сохранению данных в какой-то переменной в операцию, которая требует некоторого дополнительного интеллектуального усилия.
Когда и если они не работают, то воцаряется хаос. Получаемые данные теряют смысл. Столбцы не стыкуются. Деньги исчезают со счетов со свистом. И это всё — просто биты в памяти. И большая удача, если удастся определить какой-либо из них. В большинстве случаев разработчики заканчивают тем, что блокируют значительные участки структуры данных так, чтобы только один поток мог взаимодействовать с ними. Это позволяет остановить хаос, но только за счёт ликвидации большей части положительных сторон наличия несколько потоков, работающих на тех же данных. Вы просто могли бы переписать такую программу как «однопоточную».
Замыкания
Где-то по ходу дела кто-то решил, что было бы полезно передавать функции, как если бы они были данными. Это работало хорошо в простых случаях, но программисты начали осознавать, что возникают проблемы, когда функции стали выходить снаружи на самих себя и получать доступ к другим данным, часто называемыми «свободными переменными». Какая версия является правильной в этом случае? Данные на момент инициализации вызова функции? Или же на момент её фактической работы? Это особенно важно для JavaScript, где данные моменты могут быть сильно разнесены.
Решение — «замыкание» — является одной из самых больших причин головной боли для программистов JavaScript (а теперь и Java и Swift). Новички и даже многие опытные программисты не могут понять, что замыкается и где могли бы быть границы этого так называемого замыкания.
Название не помогает — это не похоже на предупреждение о постоянном закрытии доступа вроде предложения для посетителей паба сделать последний заказ (перед его закрытием). В любом случае доступ открыт, но только через «червоточину» в континууме данные-время — странном механизме сдвига во времени, который, должно быть, навеян научно-фантастическими сериалами. Но названия «комплексный механизм доступа к стеку» или «система манипулирования управлением данными» представляются слишком длинными, поэтому было выбрано «замыкание». И не будем начинать разговор о том, кто должен поплатиться за несвободные переменные.
Слишком большие данные
Когда ОЗУ начинает переполняться, всё падает. Не имеет значения, выполняете вы навороченный статистический анализ потребительских данных или работаете с привычной старой электронной таблицей. Когда машина выходит за пределы ОЗУ, то она обращается к т.н. виртуальной памяти, которая действует на чрезвычайно медленном (по сравнению с ОЗУ) жёстком диске или твердотельном накопителе. Это, конечно, лучше, чем полная остановка или завершение задания, но работа замедляется в любом случае.
Проблема в том, что быстродействие жёстких дисков в 20-30 раз меньше, чем у ОЗУ, а накопители, массово продаваемые на рынке, работают ещё медленнее. Если какой-то другой процесс также пытается в это время писать на диск или считывать с него, то ситуация становится просто драматической, поскольку эти накопители могут выполнять только одну задачу в каждый момент времени.
Активация виртуальной памяти обостряет другие, скрытые проблемы вашего программного обеспечения. Если имеются какие-то потоковые дефекты, то они начинают проявляться намного сильнее, поскольку потоки, попадающие в виртуальную память на жёстком диске, обрабатываются намного медленнее, чем другие потоки. Другие потоки «подвисают» лишь на то время, пока поток-неудачник находится в этой памяти. Если программа сделана хорошо, то результатом является заметное замедление. Если в программе есть дефекты, то они быстро приводят к катастрофе. И это лишь один маленький пример.
Управление подобной ситуацией является серьёзным вызовом для программистов, оперирующих большими наборами данных. Любой, кто хоть немного расслабляется при проектировании структур больших наборов данных, неизбежно заканчивает программой, работающей неприемлемо медленно. Она сможет нормально пройти несколько тестов, но реальные нагрузки отправят её штопором в отказ.
NP-полная задача
Каждый, имеющий университетское образование по информатике, знает о таинственных проблемах, скрытых за некоторым сокращением, которое редко разъясняют: «полиномиальная для недетерминированной машины Тьюринга задача поиска и принятия решения» или, иначе, NP-полная задача. Подробное их изучение занимает целый семестр курса информатики, но и в этом случае многие студенты выходят с туманным представлением. В основном о том, что никто не может решить эти проблемы из-за их исключительной трудности.
Проблемы NP-полной задачи часто являются довольно сложными — если пытаться решить их, используя просто грубый, силовой подход. Например, длительность решения "проблемы коммивояжёра" растёт экспоненциально по мере увеличения количества точек маршрута. Решение "задачи о рюкзаке" нахождением подмножества чисел, которые подходят ближе всего к некоторому значению N, требует перебора всех возможных подмножеств, число которых чрезвычайно велико. Все с опасением стараются уйти от этих проблем, потому что они являются примером одного из самых страшных компьютерных «монстров»: немасштабируемые алгоритмы.
Нюанс в том, что некоторые проблемы NP-полных задач легко решаются при некотором приближённом решении. Соответствующие алгоритмы не обещают точного решения, но дают результат, довольно близкий к точному. Они, возможно, не дадут идеального маршрута для коммивояжёра, но их решение будет отличаться от правильного лишь на несколько процентов.
Существование таких довольно хороших решений делает «драконов» только более загадочными. Никто заранее не может быть уверен, действительно ли трудны эти проблемы или же они могут быть сравнительно легко решены — если вас устроит ответ, который будет просто хорошим.
Безопасность
«Есть познанное знание — то, о чём мы знаем, что знаем», — сказал однажды на пресс-конференции Дональд Рамсфельд, министр обороны второй администрации президента США Джорджа Буша. «Есть также познанное незнание — то, о чём мы знаем, что не знаем. Но есть ещё и непознанное незнание — это то, о чём мы не знаем, что не знаем.»
Рамсфельд говорил о войне в Ираке, но то же самое справедливо и для компьютерной безопасности. Самой большой проблемой являются дыры, о которые мы даже не знаем, что они возможны. Все понимают, что необходимо сделать свой пароль трудным для разгадки; это — познанное знание. Но кто-нибудь когда-нибудь хотя бы говорил, что ваше сетевое оборудование имеет свой собственный программный уровень, спрятанный глубоко внутри? Возможность не заниматься взломом вашей ОС, а вместо этого нацелиться на данный «секретный» уровень является непознанным незнанием.
Возможность подобного проникновения можно теперь не рассматривать как «непознанную», но ведь могут существовать и другие? Мы не имеем ни малейшего понятия, возможно ли заделать дыры, если мы даже не знаем, существуют ли они. Можно тщательно защитить пароли, но существуют способы взлома, которые мы не можем даже представить себе. Работа с компьютерной безопасностью доставляет, несомненно, море удовольствия. А когда речь идёт о программировании, то мышление, ориентированное на безопасность, становится всё более важным. Нельзя перекладывать на профессионалов, занимающихся безопасностью, расчистку созданной вами путаницы.
Шифрование
Шифрование кажется мощным и неприступным, когда сотрудники правоохранительных органов стоят перед конгрессом и просят дать им официальные входы в программы, чтобы преодолеть его. Проблема состоит в том, что основная часть шифрования построена на туманном облаке неопределённости. Какие математические доказательства у нас есть для неясных допущений, вроде того, что трудно разложить на множители действительно большие числа или провести дискретное логарифмирование?
Эти проблемы, действительно, трудные? Никто публично не описал какие-то алгоритмы их решения, но это не означает, что так решения не существует. Если бы вы нашли способ подслушивать каждый разговор и проникать в любой банк, вы бы сразу сообщили об этом всему миру, что помочь заделать дыры? Или же вы промолчали бы?
Реально сложной задачей является использование шифрования в собственном коде. Даже если базовые алгоритмы, как мы полагаем, безопасные, должно быть сделано много работы по обращению с паролями, ключами и соединениями. Если будет сделана хотя бы одна ошибка и какой-то пароль останется незащищённым, то всё будет напрасно.
Управление идентификацией
Многие любят рисунок, опубликованный в газете «The New Yorker» в 1993 году, с надписью: «В интернете никто не знает, что ты собака». Он даже имеет свою собственную страницу в Википедии с четырьмя детально проработанными разделами. (В интернете мало кто знает старую шутку об анализе юмора и препарировании лягушек.)
Хорошая новость заключается в том, что анонимность может быть раскрепощающей и полезной. Плохая же в том, что мы не имеем ни малейшего понятия, как сделать что-либо, кроме анонимного общения. Некоторые программисты говорят о «двухфакторной идентификации и аутентификации», но более продвинутые устремляются к «N-факторной».
Кроме пароля и, возможно, текстового сообщения на сотовый телефон у нас совсем немного того, на что можно положиться. Считыватели отпечатков пальцев выглядят впечатляюще, но многие, кажется, готовы рассказать и показать, как такая идентификация может быть взломана (см. здесь, здесь и здесь для начинающих).
Немногое из этого имеет значение для мира пустословия в Snapchat или Reddit, но множество взломанных страниц Facebook немного обескураживает. Нет какого-то лёгкого способа заниматься в сети серьёзными вопросами, такими как собственность, деньги, здравоохранение и в значительной степени всё остальное в жизни, кроме «светского» разговора на общие темы.
Фанаты биткоинов любят высказываться, насколько надёжным может быть блокчейн, но так или иначе биткоины продолжают воровать (см. здесь и здесь). Тут у нас нет никакого реального метода для идентификации.
Надёжность измерения
Конечно, когда речь идёт о программировании, то встаёт вопрос — есть ли хотя бы способ, с помощью которого мы можем измерить сложность проблемы? Никто, на самом деле, не знает этого. Мы знаем, что некоторые проблемы решить легко, но совсем другое дело определить, насколько трудно это сделать. NP-полнота является лишь одной частью сложной попытки кодифицировать сложность алгоритмов и анализа данных. Теория полезна, но она не может предложить никаких гарантий. Заманчиво сказать, что трудно даже знать, трудна ли проблема, но это, конечно, шутка.
Комментарии (90)
VovanZ
27.11.2016 20:45+56Не нашёл в списке инвалидации кэша и придумывания названий для вещей. Разочарован.
Envek
27.11.2016 21:49+36А ещё Unicode и работы с временем. Вот где драконы роятся!
neit_kas
28.11.2016 00:07Unicode обобщил бы на кодировки в целом.
DistortNeo
28.11.2016 03:26+3Кодировки сами по себе — это ерунда по сравнению с обработкой юникода со всеми экзотическии случаями. Например, «й» может представляться как одним кодпоинтом, так и комбинацией символов «и» и кратки.
neit_kas
28.11.2016 06:41+2Ещё UTF8 радует разной длинной символов. Но среди однобайтных тоже треш есть: встречались редакторы, которые при опознании путали Win1251 с какими-то другими (уже не помню с кем).
grossws
29.11.2016 16:00Проблема, что однобайтные кодировки часто приходится угадывать, если кодировка явно не указана в метаданных, а это процесс вероятностный. На коротких текстах, например, cp1251 может быть опознан как mac-cyrillic.
neit_kas
01.12.2016 23:38У меня notepad-qq опознаёт её как iso8859-1. При этом notepad++ опознавал по-другому: какая-то очень похожая на 1251, отличия были буквально в паре букв. Точно помню 'й' и вроде 'я' страдали.
grossws
02.12.2016 00:34+1Как раз в mac cyrillic есть эта проблема. Например 0xff там
¤
, а нея
, вместоЭ -> Ё
,Ю -> ё
,Я -> я
и т. п. Ну и остальные заглавные должны страдать.
vikarti
28.11.2016 15:29Причем даже крупные компании — не всегда корректно это обрабатывают.
Пример: скопируем из ЛК мегафона какую то сумму со знаком рубля (новым) в буфер обмена а потом попробуем ее вставить в создаваемый там же тикет поддержки. Она вставится. Только вот при попытке отправить будет сообщение что ошибка (без указания деталей). если заменить символ на просто Р — все отправляется.DistortNeo
28.11.2016 15:42Мне встречался случай, когда я не мог отправить сообщение (не помню куда), содержащее в теле слово «select» — вот такая доморощенная защита от sql injection.
0x9d8e
28.11.2016 18:10Вконтакте в 2008-2009 такое творил. Точнее просто вырезал всё, что ему казалось похожим на SQL.
neit_kas
28.11.2016 00:11+2Ещё добавил бы:
3 угла треугольника: скорость выполнения, затрачиваемая память и поддерживаемость кода (поиск золотой середины).
Архитектура ПО: когда заранее не в курсе, куда занесёт и, следовательно, какую архитектуру построить.
ababo
28.11.2016 11:12Вот с именованием иногда просто беда, как бы это глупо не звучало. Порой так мучительно придумывать имя как для отдельных сущностей, так и для проекта в целом.
Pakos
01.12.2016 10:12Я придумал имя для проекта, его не поддержали… и дали следующему проекту (оказалось что ему оно подходит даже больше). Бывает и такое.
Labunsky
27.11.2016 21:49+2>Если бы вы нашли способ подслушивать каждый разговор и проникать в любой банк, вы бы сразу сообщили об этом всему миру, что помочь заделать дыры?
Один человек в масштабах планеты особой угрозы не несет. А надежность хранения тайны группой лиц стремится к нулю при увеличении размера группы, так что не стоит пока беспокоиться о ненадежности шифрования. Во всяком случае не больше, чем о рептилоидахa1111exe
28.11.2016 00:22-3Один человек в масштабах планеты особой угрозы не несет.
Ой ли? А если реинкарнация злодея Гитлера и гения Канта в одном лице, усугублённая современным высшим образованием и отсутствием внятных моральных ориентиров?poxu
28.11.2016 12:01+2А если реинкарнация злодея Гитлера и гения Канта в одном лице
Хотел написать какую-нибудь ядовитую шутку про то, что ничего гениального Канта не сделал, но передумал. Лучше спрошу вопрос.
Смог бы злодей типа Гитлера сделать что-нибудь, если б он не пользовался поддержкой такого количества окружающих его людей. И, смог бы он добиться этой поддержки, если бы они не были соответствующим образом подготовлены предшествующими обстоятельствами?
И что может сделать гений, если он даже толком коллегу подсидеть зачастую не способен?
raacer
28.11.2016 15:03И что может сделать гений, если он даже толком коллегу подсидеть зачастую не способен?
Обидеться на весь мир и взорвать ядерный реактор?poxu
28.11.2016 17:42Для того, чтобы взорвать ядерный реактор надо получить туда доступ и иметь возможность обойти все уровни защит от того, кто может обидеться на весь мир. Эта задача гораздо ближе к "подсидеть коллегу", чем к тому, чем занимается среднестатистический гений.
Alexeyslav
28.11.2016 17:45А как насчет внести небольшие изменения в систему управления чтобы накопившаяся ошибка через месяц-другой привела к аварии?
poxu
28.11.2016 18:48К системе управления надо получить доступ, потом надо молиться, что никто из контролёров этих ошибок не заметит.
a1111exe
01.12.2016 22:29Было написано «один человек в масштабах планеты особой угрозы не несёт». Мой тезис: технически возможно одному человеку угрожать благополучию всего мира. И я привёл пример, в котором человек наделён властью (Гитлер был наделён властью), умён и аморален. Такое невозможно? Серьёзно?
P.S. Позвольте спросить, чем Вам не угодил Кант?
Nordicx86
28.11.2016 10:26-1как вам сказать «коды» пуска ядерных ракет — в курсе ТОЧНО группа лиц,, но они хранятся вполне и вполне надежно.
тут ТОЖЕ САМОЕ — реально методы взлома существуют(«непознаное незнаю»), но их вам ни кто не озвучит пока вы сами не попадете в условия когда сохранение тайны станет вашим непосредственным, я бы даже добавил ЖИЗНЕННО важным интересом… ДУМАЙТЕ…Alexeyslav
28.11.2016 11:21Надёжно они хранятся потому что сменяются чаще чем происходит вероятная утечка. Кроме того, с недавних пор некоторые пусковые коды известны всем поскольку военные признали проблему что при необходимости осуществить реальный пуск в сжатые сроки ввести сложный код с первой попытки нереально, поэтому пусковые коды непосредственно на местах играют роль щеколды на деревянной двери. Поэтому однократная утечка кодов не страшна, есть и другие эшелоны защиты от несанкционированного запуска.
vikarti
28.11.2016 15:44А один человеке который патриот своей страны и сообщил метод соответствующей разведке, веря что те не использует его во вред стране? Зависит ли ответ от того — какая именно страна у сообщившего и какая страна и политические взгляды у того, кто оценивает ущерб
А если никому не сообщил но выложил в багтрекер мозиллы сертификат для mozilla.org, подписанный SubCA с CN='Klingon Empire', в свою очередь подписанный VeriSign + тоже самое но в качестве RootCA — использован допустим CNNIC и с комментарием что никто VeriSign/CNNIC не взламывал, просто современные протоколы ЭЦП — ненадежны… без указания деталей. Это вообще — угроза или предупреждение об уязвимости?
Vjatcheslav3345
27.11.2016 22:14+8В любом случае доступ открыт, но только через «червоточину» в континууме данные-время — странном механизме сдвига во времени, который, должно быть, навеян научно-фантастическими сериалами.
Кажется я теперь знаю, как понятно объяснять своей девушке проблему замыканий: "Знаешь, начнём с того, что это чем то похоже на наиновейшие теории пространства-времени, которые мы с таким удовольствием вчера обсуждали в гостях у Маньки-соседки. Давай рассмотрим [беру её за руку] такую простенькую вещь как обыкновенная «червоточина» в пространстве-времени..."
Zonzen
27.11.2016 22:40-3Статью следует назвать — «семь самых частых ошибок некомпетентных программистов».
third112
27.11.2016 22:50-3Верно. Не понятна адресация. М.б. это попытка популярной статьи для начальников, которые сами программировать не умеют? :)
third112
28.11.2016 12:27-1Ура! Статья нашла своего читателя: прибежали некомпетентные минусаторы, которым нечего возразить словами, зато минусы раздали :)) -«Аргументация» на уровне статьи!
aon24
28.11.2016 13:07+3Согласен с Вами, но не судите автора строго: он наберется опыта и поймет, что главный дракон любого программиста (любого человека) — это некомпетентность, и ее не вылечишь советами типа «нельзя создавать путаницы».
third112
28.11.2016 13:36-1Ok. Я бы еще добавил, что некомпетентность зачастую вызывает завышенную самооценку, а это совсем плохо, когда человек не считает нужным что-то узнать и чему-то научиться, просто посоветоваться. Такие горе-программисты могут быть очень разрушительны для проекта, особенно, если их несколько объединились, и если их начальник сам не сильно компетентный.
aon24
28.11.2016 14:19Не согласен с Вами. Некомпетентность не вызывает завышенную самооценку. На мой взгляд завышенная самооценка формируется при работе в слабом коллективе. Короля создает свита.
third112
28.11.2016 14:50Вспомните, нпр., «болезнь» многих первокурсников: студент чуть успел проучиться, и ему начинает казаться, что он почти специалист… Посмотрите на разных форумах в сетке — самые нетерпимые, самые убежденные в своей правоте форумчане — это недоучившиеся студенты. Причем, чем ниже курс студента — тем он больше убежден в своей правоте.
aon24
28.11.2016 16:09+1Я не случайно написал «наберется опыта и поймет...».
Я сам по юности лет, получив в Питере хорошее образование и поработав пару лет программистом, был послан в Уфу в качестве гуру поучать местных спецов (интернет только зарождался). Через пару часов общения я понял, что мои башкирские ровесники разбираются в проблеме и в программировании лучше меня :)
Пришлось самооценку скорректировать.
Alexey_Sarychev
28.11.2016 00:22+9Можно и сильнее округлить. Давайте уж сразу — «семь самых частых ошибок некомпетентных людей».
Если боксер побьет плавца, значит пловец плохой спортсмен. Точка.
Незнание одной области не делает программиста некомпетентным.
Учитывая самодурство некоторых руководителей, я могу запросто представить ситуацию, когда программисту дадут многопоточную задачу, даже если он никогда с этим не сталкивался.Zonzen
28.11.2016 08:57Незнание одной области не делает программиста некомпетентным.
По вашей логике, незнание, например, доктором биологических наук ядерной физики, не делает его некомпетентным в области этой самой ядерной физики.Alexey_Sarychev
28.11.2016 09:09Я как раз написал автору комментария тоже самое — обобщение не верно.
Если программист не умеет работать с многопоточностью, это не делает из него плохого программиста, если он, к примеру, веб-программист.
Если применить мою мысль на ваш пример, то я утверждаю, что доктор все еще будет компетентным биологом.Zonzen
28.11.2016 09:18В этих вопросах важно не стать заложником терминологии, да, и веб-программист и системный программист несут в названиях своих специализаций слово «программист», но это абсолютно разные специальности, разные уровни компетенции и ответственности. Что то вроде сравнения дальнобойщика и пилота «формулы-1».
Следовательно, Ваша фраза
Если программист не умеет работать с многопоточностью, это не делает из него плохого программиста, если он, к примеру веб-программист.
не имеет никакого смысла.Alexey_Sarychev
28.11.2016 09:34Согласен с вами, насчет терминологи. Все зависит от того, как определять множества. Поэтому поясню более формально.
Если есть множество «программист», и оно содержит подмножества «системный программист» и «веб программист», то, если объект не является системным программистом, он все еще имеет шанс прибывать в множестве программистов.
Исходя из того, что шифрование, замыкания, NP-полные задачи и многопоточность не относятся к одной конкретной областям программирования, я сделал вывод, что множество «программист» все-таки определено.
third112
28.11.2016 12:47Учитывая самодурство некоторых руководителей, я могу запросто представить ситуацию, когда программисту дадут многопоточную задачу, даже если он никогда с этим не сталкивался.
Все когда-то с чем-то сталкиваются впервые. Когда появились широкодоступные многоядерные CPU спецов по многопоточному программированию было мало. И вполне нормальный начальник мог сказать своим программистам: осваивайте новую технологию. Очень многим программистам периодически приходится заниматься самообразованием, советоваться с более опытными в возникающих вопросах коллегами в том числе и по сетке. Если у программиста хорошие базовые знания и он не лентяй, то он справляется. От начальника требуется реальная оценка трудозатрат и реальные сроки.
a1111exe
28.11.2016 00:40+9Рискую предположить, что намного больше 50% кода в настоящее время пишется программистами, которых Вы бы назвали некомпетентными. И это реальность, которой безразлично, что кому-то из компетентных гуру-программистов она не нравится. Имхо, единственный выход — культивация сообществ наподобие Хабра, где регулярно появляются материалы, призванные тем или иным образом ликвидировать ту или иную некомпетентность. Ибо книги и университеты, увы, не охватывают всё многообразие продакшена.
P.S. В идеальном мире, где все программисты компетентны, никто ни у кого ничему не может научиться. И никто никого ничему не может научить. И хуже всего в таком мире пришлось бы программистам-снобам, которым некого было бы ткнуть носом в его возмутительную некомпетентность.maxpsyhos
28.11.2016 04:42+3Никогда все не будут компетентными, потому что компетентность — это понятие относительное. В любом сообществе всегда будет кто-то лучше, а кто-то хуже среднестатистического уровня. Особенно с учётом того, что количество дисциплин всё временно растёт, и гуру многопоточных числодробилок может оказаться полным днищем в написании даже простейших интерактивных интерфейсов.
Zonzen
28.11.2016 08:52намного больше 50% кода в настоящее время пишется программистами, которых Вы бы назвали некомпетентными.
И это видно невооруженным глазом, софт с каждым годом становится хуже. А эти «намного больше 50%» должны элементарно уйти из профессии.Pakos
28.11.2016 11:02Софта станет на 50% меньше, но станет ли он лучше? Если оставшиеся программисты «размажутся» по направлениям и получится что кто-то попадёт в область своей некомпетентности и снова окажется «плохого софта 50%» и снова надо уходить половину из профессии. Повторить. Или если каждый окажется на прежнем месте, то будет вариант «мы тут сделали, но это бесполезно — наши данные никому не нужны, т.к. их некуда применять».
third112
28.11.2016 12:59ИМХО из того факта, что «софт с каждым годом становится хуже» логически не следует, что программисты стали хуже. Если хорошему программисту дать слишком сжатые сроки — он либо не выполнит задачу, либо схалтурит. Во многом виновата сетка: когда появилась возможность каждодневных автоматических обновлений, многие фирмы решили, что им выгоднее выбрасывать на рынок сырые продукты — главное опередить конкурентов. Мы живем в мире непрочных вещей и сырого софта, культура этого мира — потребительская: «покупайте как можно чаще».
Zonzen
28.11.2016 18:19-1a1111exe
01.12.2016 22:47Все джуниоры тоже? Они по определению некомпетентны.
Увы, реальность такова, что наше мнение о том, кто что кому в этом мире должен, на регулярной основе реальностью игнорируется. Короче, имхо, в подобных негативных мнениях нет ничего конструктивного, т.е., они практически бесполезны. Если человек вцепился в специальность программиста, пишет говнокод, и его такое положение дел устраивает, то можно предположить следующее:
1) человеку нравится кодить (или делать что-то из того, что включает в себя этот процесс);
2) его начальству (или заказчикам в случае фриланса) текущее качество его кода безразлично, и другие подходы ему не знакомы.
Как бы нам это не нравилось, усердный говнокодер всегда найдёт работу. И если он с накоплением опыта продолжает писать говнокод, то существенная часть вины лежит и на сообществе (от его рабочего окружения и до статей на Хабре), которое не смогло или не (достаточно) захотело мотивировать его на развитие. Не думаю, что существует много чёрно-белых ситуаций.
third112
27.11.2016 22:47ИМХО про многопоточность в принципе верно сказано. Действительно не быстро и не охотно внедряется. Но очень полезная (и зачастую необходимая) вещь, когда грамотно использована. Стоило бы CUDA упомянуть…
Про «Слишком большие данные» — очевидно. И как-то слишком примитивно. Есть разные способы сжатия данных, в одной статье не перечислить, но хоть сказать, что есть — было бы не вредно.
Про NP сказано много слишком таинственного, конспирологичного. Тут ИМХО автор пытается сесть между двух стульев: для популярного объяснения слишком непонятно, а для спецов, достаточно простого упоминания, что
P =? NP пока остается открытой проблемой.Dum_spiro_spero
28.11.2016 09:27Скорее всего это проблема нынешнего обучения программированию. Преподаватели учат тому, чему учили их.
Надо СРАЗУ со школы учить концепции многопоточности.
Как сейчас помню — э… «напишите алгоритм мытья окна». А надо так — есть четыре брата — им надо помыть окно, при этом не переругаться и не выбить это окно нафиг. Жизненный опыт подсказывает, что две последние задачи могут оказаться существенно сложнее чем первая.
lgorSL
28.11.2016 00:26NP-полная задача
Существует целая куча задач, которые проблематично вычислить без всякой np-полноты (Особенно если использовать "слишком большие данные"). Автор почему-то их не упомянул.
IIvana
28.11.2016 03:40+3Не понял сложностей с замыканиями. Джаваскрипт/свифт не курил, но на примере Scheme не мог бы кто показать драконов с ними? В тепличных условиях однопоточности и отсутствия всяких континюэйшен-пассингов.
Suvitruf
28.11.2016 08:38Часто встречал, когда в цикле используется замыкание, при этом не делая локальной копии переменной, из-за чего косяки всплывают. В C# проектах, как правило.
vanxant
28.11.2016 10:29Не знаю схему, но одна из проблем — утечки в языках с управляемой памятью (сборщиком мусора).
Допустим, вы случайно утащили в замыкание ссылку на какой-нибудь крупный объект. Допустим, на коллекцию, хотя из всей коллекции вам фактически нужен один элемент. И передали это замыкание куда-нибудь дальше, допустим, как обработчик клика по кнопке.
Ну и все. Коллекция, может, уже протухла, и ее давно пора сжечь, но сборщик мусора сделать этого не может, так как к ней есть путь ссылок от кнопки.IIvana
28.11.2016 14:51Ну это имхо условная проблема. Конечно замыкание замыкает все что видит снаружи, даже если оно ему не нужно для работы. И сборщик мусора не почистит. Но во-первых, если замыкание динамически изменяемое, то бывшее ненужное внезапно может оказаться нужным. А во-вторых, если жалко держать большой ненужный объект в памяти, переменную, с ним связанную можно (в тех языках, с которыми я сталкивался) пересетить на ноль или вообще заандефить (отбиндить или как это сказать — в общем удалить связь имя-значение в словаре связей окружения). По-русски говоря — почистить за собой мусор вручную :) Хотя, с натяжкой это наверное можно записать в драконы языков с GC.
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 переменные меняются повсеместно явно и неявно.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>]
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]
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))
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]
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
discopalevo
28.11.2016 15:54+1а теперь поменяй во втором цикле i на j, в js область видимости у переменных это функция а не блок.
raacer
28.11.2016 16:02Да, точно! Спасибо. Сам себя запутал :) Я-то думаю, что за магия с параметрами цикла… ))) Ну тогда всё предсказуемо работает, как и должно.
Тогда непонятно, почему «На первый взгляд список «fns» должен содержать функции, которые возвращают 1, 2 и 3.» Ведь все функции возвращают значение одной и той же переменной. На чей первый взгляд? Непосвященного в принцип работы замыканий — возможно. Ну так надо учить матчасть, что ли…poxu
28.11.2016 18:52Сколько не учи матчасть — простор для создания ошибок — огромный. А если вместо целого i передавать объект — станет ещё непонятнее.
raacer
28.11.2016 15:35Возможно, Вы хотели продемонстрировать что-то вроде такого?
JS: Все функции возвращают 3fns = [] 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
EvilArcher
28.11.2016 14:02Больше всего драконов там, где заказчику нужно быстро, желательно еще вчера, сделать мега-фичу за небольшой бюджет.
raacer
28.11.2016 15:01Многопоточность
…
Идея работает — когда все части являются, действительно, полностью раздельными и никак не связаны друг с другом. Но если они должны получать доступ к одним и тем же переменным или записывать биты в одни и те же файлы — игра окончена.
А как на счет ФП и чистых функций, которые без труда многопоточатся? Наверное, стоит сделать оговорку, что данная проблема присуща в основном императивному подходу, когда программист размышляет однопоточной последовательностью команд.DistortNeo
28.11.2016 15:39+1Проблема в том, что железо императивно.
raacer
28.11.2016 15:52Да, кому-то придется написать компилятор или интерпретатор, что поделаешь. Но это не значит, что многопоточность — это всегда опасно. Если есть возможность использовать ФП, то данный пункт не актуален. А в статье это преподнесено, как неизбежное зло всегда и везде: рассказано про ад семафоров, но ничего не сказано об альтернативах.
maxpsyhos
29.11.2016 04:36С ФП тоже не всё так просто. Конечно, дерево вызовов в одной функции оно распараллелит. Но это не совсем о то, о чём была речь. Каким образом ФП поможет разделить доступ к ресурсу, который используется из нескольких независимых потоков? Например, чтобы один подключенный клиент мог читать файл, а другой в это же самое время писать его?
Dark_Daiver
29.11.2016 09:02Ды, никак.
Идея чистых функций в том, что они не меняют состояние. Нет изменяемого состояния — можно параллелить сколько угодно вызовов функций, они не смогут друг другу «навредить» by design.
Запись в файл который кто-то читает, это уже изменение состояния. Как это разрулить в рамках ФП я, к сожалению, не знаю =)
sbagan
28.11.2016 15:46+1NP-полная задача != NP задача, NP-полная — любую NP задачу можно к ней свести(например задача коммивояжера — NP-полная), определение которое тут написано — просто задача из класса NP, к тому же практической ценности в NP не так много(хотел бы посмотреть как будут масштабировать n^100, это же из P задача:)
grossws
29.11.2016 15:57Когда машина выходит за пределы ОЗУ, то она обращается к т.н. виртуальной памяти, которая действует на чрезвычайно медленном (по сравнению с ОЗУ) жёстком диске или твердотельном накопителе. Это, конечно, лучше, чем полная остановка или завершение задания, но работа замедляется в любом случае.
Гнать ссаными тряпками. КГ/АМ, в общем, если выражаться прямо.
Виртуальная память у него на hdd/ssd. А к оперативке он, видимо, доступ не через MMU получает, а через libastral.
FirsofMaxim
В Swift для замыканий ввели типы аргументов — weak/unowned, внутри при доступе к вызываемому контексту требуется написать self, тем самым среда как бы говорит — «ага! self написал — утечку осознал!» (здесь я имею ввиду что если в замыкании используется self без типа аргумента weak/unowned — привет утечка)
storoj
ничего и не утечка
FirsofMaxim
а вот и утечка если:
1) замыкание
2) внутри self
3) self не указан как weak/unowned
Немного хелпа тут
self связывается как strong ссылка если не указано иное.
storoj
dispatch_async({ print(self) }) – тоже утечка?
FirsofMaxim
Если ссылка на очередь нигде не сохраняется, то конечно утечки нет, но все меняется если пробовать вызвать код в main очереди, например (Swift3):
Запустите в Playground этот код:
##########
A init
A.fooBar
A.fooBarAsync
Ухты! Где deinit растак его?!
Делаем так:
##########
A init
A.fooBar
A.fooBarAsync
A deinit
Оуе детка! Я тебя вижу :)
storoj
Рекомендую добавить это в начало:
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
А в последнем примере по коду разве не должен был быть ещё один A.foobar после deinit? Может быть его нет потому что всё благополучно упало?
FirsofMaxim
Все работает без падений, попробуйте.