Джеймс Миккенс знает, что почем: The Night Watch.

Всем программистам очень рекомендую. Очень смешно и правдиво.

На фразе

What is despair? I have known it — hear my song. Despair is when you’re debugging a kernel driver and you look at a memory dump and you see that a pointer has a value of 7.

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

Еще один отрывок:

You might ask, “Why would someone write code in a grotesque language that exposes raw memory addresses? Why not use a modern language with garbage collection and functional programming and free massages after lunch?” Here’s the answer: Pointers are real. They’re what the hardware understands. Somebody has to deal with them. You can’t just place a LISP book on top of an x86 chip and hope that the hardware learns about lambda calculus by osmosis. Denying the existence of pointers is like living in ancient Greece and denying the existence of Krackens and then being confused about why none of your ships ever make it to Morocco, or Ur-Morocco, or whatever Morocco was called back then. Pointers are like Krackens — real, living things that must be dealt with so that polite society can exist.
Это цинично и в целом верно - такой режим работы действительно помогает идти вверх по служебной лестнице в больших софтверных компаниях:
Career Driven Development Manifesto

Main principles of effective software development in a big company.
  1. Know people who really make decisions about your promotion. It’s not necessary your immediate manager or even your skip manager.

  2. Do whatever it takes to work only on projects and features that are visible and valuable to people from point 1.

  3. If it just works, it’s good enough. Don’t waste time on processes, design docs, tooling improvements, new technologies, refactorings, unit tests. These things never get you promoted.

  4. You don’t really need a feature to work, all you need is to make people think it works.

  5. Don’t let anyone shadow you. Represent your work on any level you can reach.
(эта запись может быть интересна программистам и сочувствующим)

Наконец-то кто-то сделал важное и правильное дело: выложил в открытый доступ действительно качественное, основанное на правильных принципах решение известной проблемы FizzBuzz:

FizzBuzz Enterprise Edition

Я читал исходники и восхищался. Практически не к чему придраться, ну разве что я бы еще тестов добавил. Но само решение - высший класс.
Prince of Persia Code Review

Анализ исходников "Принца", которые в прошлом году отыскал на старой дискете и выложил на github его создатель. Это самая первая версия игры, которая работала на Apple II и написана на ассемблере 6502. Пока что там в основном обсуждается bootloader, но уже есть захватывающие подробности - в частности нестандартное форматирование дискеты специально для этой игры, чтобы уместить больше килобайт на дискете и заодно как форма copy protection.

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

Pair Programming - My Personal Nightmare

Цитата оттуда:
When people describe pair programming as a practice that they benefit from, cool, I get that. But when they take the next leap and advocate (or mandate) the practice for me, because they "know" I'll benefit from it (and have "data" to prove it!), slow down. The methods by which people produce quality work are as varied as we are. [...] To claim that pair programming is a "best practice" for all is foolish, I don't care what the agile dogmatists say.

Я согласен с основными мыслями в этой записи. Я бы не сказал "my personal nightmare", это слишком мелодраматично, но я не люблю писать код вдвоем, и у меня это обычно хуже получается, чем работать в одиночку. Есть исключения, когда это полезно, например, разобраться вместе в непонятном коде, найти хитрую ошибку, быстро настрочить прототипный код. Но в качестве постоянной практики - нет, мне тяжело, я быстро устаю и раздражаюсь на себя самого, и код выходит хуже, чем в одиночку.
Вот это очень круто, по-моему. Они придумали усиливать крохотные цветовые изменения, невидимые невооруженным взглядом, так, что после обработки видно биение сердца человека, движение крови вдоль кожи, дыхание младенца, итд. Очень впечатляет.

_GET и mysql_query вместе

75 тысяч результатов.

Это из реддита с прекрасным названием lolphp, в котором есть много смешного - например, вот эта лошадь:

Я беседовал сегодня с Г. о разных способах выразить то же самое на C/C++ и смежных языках, и действительно ли это влияет на быстроту и качество чтения и понимания кода. Вообще говоря в последние годы я обнаруживаю в себе все больше и больше неприязни к "хитрым" способам что-то выразить в коде, более лаконичным, чем простой и наивный способ сказать то же самое, даже если он занимает больше строк кода. Почти все "хитрые" трюки привлекают к себе внимание и задерживают это внимания на себе, снижают скорость чтения кода и ясность его понимания. Но ровно то же самое я мог бы сказать и пять лет назад, а вместе с тем мое отношение изменилось еще дальше в сторону против трюков; наверное, мне нравится в коде еще большая ясность и прозрачность, чем раньше, и "трюками" я считаю вещи, которые другие программисты, наверное, сочтут совсем обыденными. Не захожу ли я в этом слишком далеко?

Вот два примера - мелких, и, может, даже мелочных, но иллюстрируют тему.

Пару лет назад мы говорили с Г. ровно о том же и тогда я сказал ему: в юности меня раздражала идиома работы с указателем if (p != NULL), и вместо нее в своем личном коде я всегда писал if (p) (и еще указателям присваивал 0, а не NULL). А сейчас, сказал я, предпочту первый вариант. Попытался объяснить, почему: когда читаешь такой код, как if(p), то пусть на долю секунды, но твое внимание отвлекается на него и ты делаешь приведение типов "в уме". Я могу сколь угодно твердо знать и помнить, что именно означает указатель в булевом контексте, но когда я читаю строки кода до того, я все равно помню, что вот это - указатель, а вот это - булево (логическое) выражение, и они совершенно разные вещи. Оператор != дает мне перейти от одного к другому, совершенно не задумываясь об этом переходе, именно потому, что он есть, этот оператор, он явно говорит: сейчас я вам дам булевое значение. А в случае if(p) мне нужно этот переход сделать самому, и это хоть на крохотную долю секунды, но отвлекает меня от действительно важных вещей.

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


1. return results > 0;


или


2. if (results > 0) {
  return true;
} else {
  return false;
}


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

У меня есть два аргумента против первой формы. Во-первых, почему это "трюк", почему привлекает внимание? Потому что мы относимся (кстати, прошу помнить, что я говорю о себе, все эти "мы" условные и гипотетиечские, если у вас это устроено по-другому, я не против), так вот, мы относимся к булевым значениям иначе, чем к целым числам, строкам, числам плавающей точкой. Все эти типы для нас - единицы информации, а булевы значения, как бы это сказать, единицы решения (information units и decision units). Мы привыкли в коде видеть булевы значения в одном из трех контекстов: 1) литералы true/false в аргументах и возвратных значениях функций; 2) внутри контрольных структур: if while for итд.; 3) аргументы логических операторов == != < итд. Причем третий контекст обычно содержится внутри второго, контекста "решения, что делать", а первый тоже можно считать его под-видом, только отдаленным во времени, но особенно прозрачным образом (скажем, если мы вернули true, то ожидаем, что кто-то тут же с этим значением сделает что-то "решительное", связанное с решением). Все другие использования булевых значений оказываются "странными" и привлекают наше внимание. Я не хочу эту "странность" преувеличивать, она, может, минимальна, и конечно при чтении все очевидно, но все же она есть. Иногда эта странность оправдана, потому что ее требует логика задачи. Скажем, при вычислении сложных и запутанных булевых значений стоит положить промежуточный результат в переменную. Или хранить в булевой переменной done условие окончания цикла. Или держать вектор булевых значений для чего-то. Во всех этих случаях, конечно, надо использовать булевые значение в этих немного более редких контекстах (хотя насчет "done" я не уверен - он настолько обычен, что редким трудно счесть, может, его стоит записать в собратья первого пункта выше), что поделать, это нужно "для работы". А в "return results > 0" это использование булевого значения скорее несколько фривольное, чем "для работы", поэтому крохотная задержка внимания, которого оно требует, неоправдано.

О втором аргументе я подумал чуть позже, и вот он какой. Я пытался наблюдать за собой, как именно я воспринимаю "return results > 0". И вдруг понял, как это охарактеризовать: зная, что функция возвращает булевое значение, я неизбежно, читая эту строку, делаю в уме такой небольшой танец на месте. Я думаю (пусть не словами, а сильно сокращенными ощущениями, но все же): "если больше нуля, то true, если нет, то false". Если так, то так, а если нет, то этак. Шаг влево - так, шаг вправо - этак. Выходит, что я в уме продумываю ровно то же, что и при чтении более длинной формы с if (results > 0). Но если она все равно у меня в уме возникает, так пусть и на экране будет. Несовпадение знаков на экране и продумывания в уме и вызывает это крохотную задержку при чтении, и ситуация тут аналогична if(p). А вот, скажем, если бы было написано что-то вроде "return IsPositive(results);", то это у меня не вызывает танца в уме, тут нет никакой задержки. Танец как бы откладывается до того момента, когда я прочитаю код IsPositive. (Это не значит, конечно, что надо именно так писать - у дополнительной функции и дополнительного уровня косвенности есть своя когнитивная цена. Я лично так писать не стану.)

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

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

Вот, подумал, может не мне одному интересно.
People of ACM: Christos Papadimitriou

Небольшое интересное интервью с Христосом Пападимитриу, которого я лично знаю как автора любимого учебника по теории сложности (Computational Complexity 1994 года; возможно, недавний учебник Arora & Barak презвошел его, не знаю, не читал; кстати, есть мнения на эту тему?). Еще он один из соавторов отличного учебника алгоритмов (Dasgupta, Papadimitriou, Vazirani, Algorithms), и автор популярного комикса про логику и теорию множеств (!) Logicomix.

Пападимитриу упоминает, что у него был студентом Билл Гейтс, до того, как бросил учиться, чтобы основать Майкрософт. Я не знал, что они написали вместе статью:
When I was an assistant professor at Harvard, Bill was a junior. My girlfriend back then said that I had told her: "There's this undergrad at school who is the smartest person I've ever met."

That semester, Gates was fascinated with a math problem called pancake sorting: How can you sort a list of numbers, say 3-4-2-1-5, by flipping prefixes of the list? You can flip the first two numbers to get 4-3-2-1-5, and the first four to finish it off: 1-2-3-4-5. Just two flips. But for a list of n numbers, nobody knew how to do it with fewer than 2n flips. Bill came to me with an idea for doing it with only 1.67n flips. We proved his algorithm correct, and we proved a lower bound—it cannot be done faster than 1.06n flips. We held the record in pancake sorting for decades. It was a silly problem back then, but it became important, because human chromosomes mutate this way.

Two years later, I called to tell him our paper had been accepted to a fine math journal. He sounded eminently disinterested. He had moved to Albuquerque, New Mexico to run a small company writing code for microprocessors, of all things. I remember thinking: "Such a brilliant kid. What a waste."


Вот эта статья: Gates, Papadimitriou. Bounds For Sorting By Prefix Reversal. Алгоритм Гейтса несложен для понимания и вполне остроумен.
На работе есть внутренняя библиотека на C++, у которой есть популярный интерфейс. Некоторое время назад в интерфейсе обнаружился хитрый баг, который вытекает из самого дизайна. Соответственно этот API заменили на другой, но сам код просто так удалить пока не смогли, слишком много пользователей, которые еще не мигрировали. В результате файл .h сейчас начинается так:


// See [omitted] and [omitted] instead.
//
// There is a known bug in this implementation of [omitted]
// that can cause deadlock.
//
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
// deprecated deprecated deprecated deprecated deprecated deprecated
Расскажите, как вы научились программировать? В каком возрасте вы написали свою первую серьезную программу, на каком языке и компьютере, что она делала?

В 12 лет мне подарили программируемый калькулятор Электроника МК-52, и я загонял в него готовые программы из "Техники - молодежи" (который мы выписывали) и "Науки и жизни". Но сам писал только тривиальные примеры, и программированием это не считаю. Были умельцы; старший товарищ [livejournal.com profile] luarvique, например, написал в этом калькуляторе программу для решения кубика Рубика, если память не изменяет. Но мне не хватало для таких подвигов знаний и терпения.

В 13 лет - я начал ходить заниматься на настоящих компьютерах (!!!) в местном пединституте, где был компьютерный класс Yamaha MSX1 (по знакомству; там преподавал отец старшего товарища, и я ему безмерно благодарен). Молодое поколение не знает, наверное, что это было. 64KB памяти, восьмибитный микропроцессор Z80, зашитый в ROM интерпретатор Бейсика, который запускался по умолчанию, когда включали компьютер. Один центральный компьютер с цветным экраном (!!!) и дисководом, и дюжина периферийных, с монохромным зеленым монитором и приводом для чтения программ с магнитофонных кассет. Все компьютеры объединены в локальную сеть, и с центрального (который простым смертным не доверяли) можно было запускать программы на периферийных.

Моими первыми настоящими языками были Бейсик и ассемблер Z80. Первыми серьезными программами были простые игрушки, а также программа на Бейсике для вычисления числа пи, которой я гордился; она пользовалась, если не ошибаюсь, формулой Мэчина, про которую я сам нашел и прочитал в математической энциклопедии после того, как вначале попробовал более простую формулу, и убедился, что она очень медленно сходится. Когда я в 15 лет уехал в Израиль, то взял с собой трехдюймовую дискету, на которой было несколько любимых игрушек и исходники этой программы; эта дискета потом потерялась.

На MSX можно было делать довольно мощные игрушки на Бейсике благодаря аппаратной поддержке спрайтов (небольших битмапов, которые записывались отдельно в видеоконтроллер, и потом двигались по экрану атомарными операциями, заслоняя друг друга в определенном порядке). Перерисовывать весь экран несколько раз в секунду не получилось бы, Бейсик не успевал, но спрайты двигать было легко. Когда мне стало не хватать скорости, я начал добавлять куски на ассемблере, вставленные прямо из Бейсика (командой POKE). Потом я освоил операционные системы MSX-DOS (вариант MS-DOS 1.0) и CP/M, которые можно было загрузить из дискеты или кассеты вместо Бейсика. На ассемблере в них можно было писать целые отдельные программы. Довольно скоро в пединституте установили второй класс компьютеров помощнее, MSX2 (128KB памяти!!!). А еще через год, когда мне было 14, такой же класс установили даже в моей школе.

Постепенно я перешел на Турбо Паскаль, но не могу вспомнить, какие программы я на нем писал. А в 15 лет я уехал в Израиль, где про MSX никто ничего не знал. Через несколько месяцев мы купил свой собственный компьютер (!!!), он был на основе Intel 80486DX.

Расскажите о том, с чего вы начали программировать, и какие первые нетривиальные программы писали?

(P.S. у меня была похожая запись в прошлом, но там говорили почти исключительно о компьютерах, а в этой мне захотелось вспомнить именно программы, которые я писал)
Хорошее название класса:
Beautiful Soup uses a class called UnicodeDammit to detect the encodings of documents you give it and convert them to Unicode, no matter what. If you need to do this for other documents (without using Beautiful Soup to parse them), you can use UnicodeDammit by itself.
Некстати: я всегда полагал, что название библиотеки BeautifulSoup - аллюзия на песню у Кэрролла, но на официальном сайте и странице Википедии нигде не вижу подтверждения этому; неужели совпадение? Думаю, все-таки нет.

P.S. Еще мне "UnicodeDammit" напомнило Programming, Motherfucker.
The Matasano Crypto Challenges выглядят довольно интересно. Особенно тем, кто совсем незнаком с современной криптографией, может быть и полезно, и интересно попробовать. Мачей Цегловски недавно их прошел и подробно описал свои впечатления.
Совет про то, как понять монады, из презентации What I Wish I Knew When Learning Haskell:
Eightfold Path to Monad Satori

  1. Don't read the monad tutorials.
  2. No really, don't read the monad tutorials.
  3. Learn about Haskell types.
  4. Learn what a typeclass is.
  5. Read the Typeclassopedia.
  6. Read the monad definitions.
  7. Use monads in real code.
  8. Don't write monad-analogy tutorials.
Мне особенно нравится, как последний пункт замыкает круг, начатый первым.

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

eclipse
Если скомпилировать и запустить вот эту программу из Obfuscated C Contest, 2006:


main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}


то она покажет время в таком формате:

    !!  !!!!                !!  !!!!            !!!!!!  !!!!!! 
    !!  !!                  !!  !!              !!  !!  !!  !! 
    !!  !!                  !!  !!              !!  !!  !!  !! 
    !!  !!!!      !!        !!  !!!!      !!    !!  !!  !!!!!! 
    !!  !!  !!              !!  !!  !!          !!  !!  !!  !! 
    !!  !!  !!              !!  !!  !!          !!  !!  !!  !! 
    !!  !!!!!!              !!  !!!!!!          !!!!!!  !!!!!! 



Как она это делает? Я сознательно не читаю объяснения на stackoverflow и разбираюсь сам; если вы хотите, можете попробовать тоже сами разобраться или проследить мой анализ.

Будем потихоньку приводить программу к читабельному виду. Вместо _ переименуем аргумент main в привычный argc, отделим первую строку и вставим в нее пробелы:


main(argc) {
  argc ^ 448 && main( - ~ argc);
  putchar(--argc%64?32|-~7[__TIME__-argc/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[argc*2&8|argc/64]/(argc&2?1:8)%8&1:10);
}


Мы помним, что argc при запуске программы без аргументов равен 1 (потому что argv, который тут игнорируется, включает в себя первым элементом имя программы).
Если argc XOR 448 равно нулю, тогда часть после && не будет выполняться, и после длинного вызова putchar() функция завершится. Если же не равно нулю, то выполнится рекурсивный вызов со значением "- ~ argc"; что это такое? ~ это побитовая инверсия, т.е. все единицы в нули и наоборот; и к этому мы применяем арифметический минус.
Вспомним, что в стандартном представлении "дополнение до 2" применить минус это "инверсия всех битов, а потом плюс 1". Значит, "- ~ argc" означает "инверсия, потом еще инверсия, потом плюс 1", или просто +1.

Поскольку argc начинается с 1, условие argc^448 не станет равно нулю, пока argc не вырастет до 448, а дальше он расти уже не будет, потому что не будет рекурсивных вызовов. Значит, это условие можно заменить просто на сравнение.

Неконец, в огромном вызове putchar пока что обратим внимание, что тернарный оператор argc%64? простирается до самого конца.

Следующая версия кода:
Read more... )
1. [livejournal.com profile] plakhov протестует против слишком наивного и устаревшего подхода к анализу климатических данных в эпоху machine learning.
Я не настолько хорошо разбираюсь в этом, чтобы иметь свое мнение о его критике, но может, кому-что еще будет интересно.

2. Как раз сегодня попалась статья: A Few Useful Things to Know about Machine Learning. Довольно хорошая, по-мовму.
1. Кто-то почистил, откомментировал и сделал немного более понятным код знаменитого JSLinux Фабриса Белльярда. Самое интересное - гигантский файл cpu86-ta.js, который вполне нормально читается, несмотря на огромный размер, и содержит полностью эмуляцию усеченного варианта 32-битного x86-процессора.

2. кто-то другой тоже был вдохновлен JSLinux, и написал свой собственный эмулятор, под которым бежит Линукс: JSLM32, исходники. Он выбрал для эмуляции старый 32-битный RISC-процессор, а не x86.

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

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

March 2014

S M T W T F S
       1
2 3 4 5 6 7 8
9 10 11 12 131415
16171819202122
23242526272829
3031     

Syndicate

RSS Atom

Style Credit

Expand Cut Tags

No cut tags
Page generated Jun. 24th, 2017 12:16 am
Powered by Dreamwidth Studios