Pull to refresh
1748
9.2

Переводчик-фрилансер

Send message

Если вы собираетесь сидеть и ничего не делать, то хотя бы делайте это правильно

Level of difficulty Easy
Reading time 4 min
Views 4K

Иногда бывает нужно, чтобы API не делал ничего. При этом важно, чтобы он не делал ничего правильным образом.

Например, у Windows есть сложная инфраструктура печати, но этой инфраструктуры нет у Xbox. Что должно произойти, если приложение попытается выполнить печать на Xbox?

Неправильно было бы, если бы функции печати выбрасывали Not­Supported­Exception. Установленное пользователем на Xbox приложение, вероятно, в основном (если не исключительно) тестировалось на PC, где печать всегда доступна. При запуске на Xbox исключение, скорее всего, не будет обработано, и приложение вылетит. Но даже если приложение попытается перехватить исключение, то, вероятно, отобразит сообщение типа «Ой. Что-то пошло не так. Обратитесь в службу поддержки и сообщите ей вот этот код ошибки».

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

Чтобы учесть ситуацию, когда приложение говорит «О, у тебя не установлены принтеры, давай помогу в установке», функция установки принтера может немедленно выполнять возврат с кодом результата, означающим «пользователь отменил операцию».

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

Читать далее
Total votes 17: ↑15 and ↓2 +13
Comments 8

Тёмные паттерны UX себя не оправдывают

Level of difficulty Easy
Reading time 3 min
Views 4.3K

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

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

Я нажал на крестик в правом верхнем углу рекламного блока. И именно тогда всё пошло не так.

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

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

Читать далее
Total votes 17: ↑15 and ↓2 +13
Comments 8

Как языковая модель предсказывает следующий токен (часть 1)

Reading time 27 min
Views 6.5K

Я обучил небольшой (порядка 10 миллионов параметров) трансформер по превосходному туториалу Let’s build GPT: from scratch, in code, spelled out Андрея Карпати. После того, как он заработал, я захотел максимально глубоко понять, как он устроен внутри и как создаёт свои результаты.

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

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

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

Читать далее
Total votes 27: ↑27 and ↓0 +27
Comments 5

Почему OKR — это отстой

Level of difficulty Easy
Reading time 7 min
Views 23K

Наверно, многие из моих читателей как раз закончили квартальный (и/или годовой) цикл планирования, так что сейчас будет подходящее время напомнить, что процесс, которым мы пользуемся как стандартом в технологической отрасли, на самом деле — полная чушь. Разумеется, я имею в виду методологию Objectives and Key Results. Давайте же поговорим об OKR, что это такое и откуда они взялись, а ещё о том, почему это ужасная идея.

Читать далее
Total votes 59: ↑53 and ↓6 +47
Comments 26

Поисковый движок в 80 строках Python

Reading time 11 min
Views 11K

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

Давайте поговорим о целях. Слышали когда-нибудь о «кризисе сложности обнаружения маленьких веб-сайтов»? Проблема в том. что маленькие веб-сайты наподобие моего невозможно найти при помощи Google или любого другого поискового движка. Какова же моя миссия? Сделать эти крошечные веб-сайты снова великими. Я верю в возвращение славы этих малышей вдали от SEO-безумия Google.

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

Кроме того, мне стоит признаться, что в заголовке поста я слегка преувеличил. Да, поисковый движок действительно реализован примерно в 80 строках Python, но я ещё и писал вспомогательный код (краулер данных, API, HTML-шаблоны и так далее), из-за которого весь проект становится немного больше. Однако я считаю, что интересная часть проекта находится в поисковом движке, который состоит из менее чем 80 строк.

P.S. Написав этот пост и microsearch, я осознал, что пару лет назад нечто похожее написал Барт де Гёде. Моя реализация очень похожа на работу Барта, но я считаю что кое-что улучшил, в частности: (1) мой краулер асинхронный, что сильно ускоряет работу, (2) я реализовал пользовательский интерфейс, позволяющий взаимодействовать с поисковым движком.

Читать далее
Total votes 29: ↑29 and ↓0 +29
Comments 4

Как я уменьшил размер образа docker на 40%

Level of difficulty Easy
Reading time 16 min
Views 15K

Ежедневно по работе я сталкиваюсь с Dockerfile, написал несколько из них самостоятельно, создавал контейнеры и всё такое. Но я никогда не публиковал их в реестре docker hub. Мне хотелось создать ugit — инструмент для отмены команд git (написанный в виде шелл-скрипта), который бы могли использовать люди, не любящие устанавливать случайные шелл-скрипты из Интернета.

Да-да, знаю. НАДО ПЕРЕПИСАТЬ ЕГО НА GO/RUST/ЕЩЁ КАКОМ-ТО ВОЛШЕБНОМ ЯЗЫКЕ. Сейчас скрипт состоит из пятисот с лишним строк Bash, поэтому я перепишу его на другой язык только под страхом смертной казни. Кроме того в ugit уже есть практически все функции (осталось реализовать отмену лишь небольшого количества команд, используемых не так часто).

В этой статье я расскажу о том, как написал официальный Dockerfile для ugit (шелл-скрипта) и снизил размер образа почти на 40% (с 31,4 МБ до 17,6 МБ), выполняя пошаговые попытки работы по инструкции. Надеюсь, это замотивирует других любителей шелла тоже публиковать свои скрипты в виде образов docker!

Читать далее
Total votes 23: ↑22 and ↓1 +21
Comments 50

Как устроена страничная организация памяти x86_64

Level of difficulty Easy
Reading time 15 min
Views 8.3K

В этом посте я буду говорить о страничной организации только в контексте PML4 (Page Map Level 4), потому что на данный момент это доминирующая схема страничной организации x86_64 и, вероятно, останется таковой какое-то время.

Окружение

Это необязательно, но я рекомендую подготовить систему для отладки ядра Linux с QEMU + gdb. Если вы никогда этого не делали, то попробуйте такой репозиторий: easylkb (сам я им никогда не пользовался, но слышал о нём много хорошего), а если не хотите настраивать окружение самостоятельно, то подойдёт режим практики в любом из заданий по Kernel Security на pwn.college (вам нужно знать команды vm connect и vm debug).

Я рекомендую вам так поступить, потому что считаю, что самостоятельное выполнение команд вместе со мной и возможность просмотра страниц (page walk) на основании увиденного в gdb — хорошая проверка понимания.

Читать далее
Total votes 53: ↑53 and ↓0 +53
Comments 0

HTML: плохие стороны

Level of difficulty Easy
Reading time 12 min
Views 4.2K

Вероятно, вы слышали заявления типа «HTML и так по умолчанию обладает accessibility» или «Не нужно изобретать заново этот абсолютно идеальный элемент управления HTML». Я считаю, что это общие заявления, а не универсальные истины. Веб-разработчикам крайне важно осознавать недостатки платформы, поэтому я решил собрать несколько примеров того, когда у HTML возникают трудности как с точки зрения accessibility, так и usability.

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

Читать далее
Total votes 16: ↑15 and ↓1 +14
Comments 16

Призыв писать компактное ПО, версия 2024 года (с примером кода)

Level of difficulty Easy
Reading time 11 min
Views 34K

Этот пост посвящён памяти Никлауса Вирта, первопроходца в сфере вычислительных наук, ушедшего от нас 1 января этого года. В 1995 году он написал важную статью A Plea for Lean Software, и в своём посте я постараюсь воспроизвести её почти тридцать лет спустя, с учётом современных кошмаров разработки ПО.

Очень короткая версия поста: современные способы разработки/сборки ПО смехотворны, они приводят к созданию пакетов на 350 МБ для рисования графиков, а простые продукты импортируют 1600 зависимостей неизвестного происхождения. Уровень безопасности ПО ужасен, ведь он зависит и от качества кода, и от его объёма. Многие из нас понимают, что ситуация нерациональна. К сожалению, многие программисты (и их руководство) никогда не работали как-то иначе. А остальным редко выделяют время, чтобы выполнять работу качественно.

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

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

Читать далее
Total votes 150: ↑147 and ↓3 +144
Comments 197

Делаем двоичные файлы Rust меньше по умолчанию

Level of difficulty Medium
Reading time 6 min
Views 4.8K

Вы когда-нибудь пробовали компилировать program helloworld на Rust в режиме --release? Если да, то видели, какой размер двоичного файла получается? Достаточно сказать, что он не очень маленький. Или, по крайней мере, не был таким до недавнего времени. В этом посте я расскажу, как узнал об этой проблеме и попытался устранить её в Cargo.

Читать далее
Total votes 38: ↑38 and ↓0 +38
Comments 13

Пишем трассировщик лучей для ZX Spectrum

Level of difficulty Easy
Reading time 16 min
Views 20K

Я люблю трассировщики лучей и даже посвятил им половину своей книги. Менее известна моя любовь к ZX Spectrum — домашнему компьютеру 1982 года, с которым я вырос и с которого начался мой интерес к графике и программированию. По современным стандартам эта машина столь смехотворно слаба (и даже по стандартам 1980-х), поэтому возникает неизбежный вопрос: в какой степени удастся портировать трассировщик лучей из книги Computer Graphics from Scratch на ZX Spectrum?

В ZX Spectrum установлен процессор Z80 на 3,5 МГц (в тысячу раз медленнее, чем современные компьютеры), который не может умножать числа (!!!), и 48 КБ ОЗУ (в миллион раз меньше); он имеет графический режим 256x176 (примерно в двести раз меньше современного разрешения), способный отображать 15 цветов (в миллион раз меньше, к тому же с довольно необычными особенностями). Интересная машина для графического приложения, активно задействующего CPU!

Я планирую реализовать его на Sinclair BASIC — встроенном языке программирования Spectrum. Это не просто BASIC, а древний, очень ограниченный диалект BASIC. Например, единственные структуры управления в нём — это FOR и IF (а у IF нет ELSE и даже ENDIF); все переменные глобальны; не существует вызовов функций, только GO TO и GO SUB; и так далее. Кроме того, он интерпретируемый, то есть сверхмедленный. Но, по крайней мере, он реализует программное умножение! Если мне нужна будет производительность, то я всегда могу переписать трассировщик на ассемблере.

Я настроил минимально необходимую среду: код на BASIC я пишу в VS Code, компилирую его с помощью BAS2TAP и запускаю в эмуляторе FUSE. Благодаря этому скорость итераций оказалась достаточно высокой.

Читать далее
Total votes 142: ↑141 and ↓1 +140
Comments 85

Старая ошибка Unix, которую вы можете совершить при сигнале init (PID 1)

Level of difficulty Medium
Reading time 2 min
Views 3.9K

Init — традиционное имя для программы, которая выполняется как process ID 1, главный наследник всех процессов Unix, исторически отвечающий за управление системой. Process ID 1 настолько критичен для системы, что его или невозможно убить, или система перезапускается при выходе из него (или и то, и другое, тогда этот перезапуск — хак). Сегодня в Linux PID 1 необязательно оказывается двоичным файлом и процессом с именем init в буквальном смысле, в отличие от *BSD, где init остаётся двоичным файлом.

Исторически сложилось так, что по множеству причин системный администратор отправляет сигналы в init, что задокументировано для современных систем Unix, например, на странице руководства к  init(8) FreeBSD. Одна из причин заключается в том, чтобы считывать заново список последовательных портов. Традиционно и даже сегодня это выполнялось отправкой init сигнала SIGHUP.

Программа kill долгое время поддерживала отправку сигналов по имени, но сисадмины ленивы и мы обычно запоминали что SIGHUP — это сигнал 1 (а сигнал 9 — это SIGKILL). Поэтому довольно часто мы вводили kill -1 1 для отправки сигнала 1 (SIGHUP) к process ID 1 (init). Однако эта версия немного опасна, потому что она лишь на один символ отличается от версии с совершенно другими эффектами.

Читать далее
Total votes 26: ↑25 and ↓1 +24
Comments 2

Сравнение производительности dict() и {} в Python

Level of difficulty Medium
Reading time 11 min
Views 15K

Какое-то время назад, во время разбора кода, мы обсудили выбор dict() вместо {} в новом коде на Python. Коллега утверждал, что dict() более читаем и чётче выражает цель, поэтому следует предпочесть его. Меня это не убедило, но в тот момент контраргуентов не нашлось, поэтому я воздержался.

Это заставило меня задуматься: в чём разница между типом dict и литеральным выражением {}?

Давайте изучим этот вопрос.

Читать далее
Total votes 26: ↑23 and ↓3 +20
Comments 19

Почему текст в нижнем регистре сжимается лучше

Level of difficulty Easy
Reading time 7 min
Views 11K

Буквы в нижнем и верхнем регистре содержат одинаковое количество данных — по 1 байту каждая.

Поэтому удивительно, что замена заглавных букв на строчные снижает объём данных.

Пример: я взял главную страницу Hacker News и переписал заголовок каждой статьи, капитализировав только первые буквы в предложениях (sentence case) вместо первых букв во всех словах (title case). Это позволило мне снизить размер на 31 байт.

Sentence case: The cat sat on the mat

Title case: The Cat Sat on the Mat

Как может замена нескольких заглавных букв на строчные снижать объём? Всё дело в сжатии.

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

Читать далее
Total votes 41: ↑32 and ↓9 +23
Comments 28

Когда Random совсем не случаен

Level of difficulty Medium
Reading time 7 min
Views 20K

Этот пост — рассказ об истории, случившейся больше десятка лет назад; её код был мной утерян. Поэтому прошу простить меня, если я не вспомню точно все подробности. Кроме того, некоторые подробности упрощены, чтобы от этой статьи могли получить все, кому нравится компьютерная безопасность, а не только любители World of Warcraft (хотя, полагаю, диаграмма Венна этих двух групп сильно пересекается).

Когда мне было примерно 14 лет, я узнал об игре World of Warcraft компании Blizzard Games, и она сразу же меня увлекла. Вскоре после этого я нашёл аддоны, позволявшие модифицировать внешний вид и функциональность интерфейса игры. Однако не все скачанные мной аддоны делали именно то, что мне было нужно. Мне хотелось большего, поэтому я начал разбираться, как они сделаны.

Забавно, что в моём серьёзном увлечении программированием можно обвинить World of Warcraft. Оказалось, что код был написан на языке Lua. Аддоны — это просто парочка файлов исходного кода на .lua в папке, напрямую загружаемых в игру. Барьер входа был невероятно низок: достаточно отредактировать файл, сохранить его и перезапустить интерфейс. То, что игра загружала твой исходный код и ты мог видеть его работу, было настоящим волшебством!

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

Читать далее
Total votes 117: ↑116 and ↓1 +115
Comments 42

Кто на самом деле пользуется is-odd и is-even?

Level of difficulty Easy
Reading time 4 min
Views 15K

Разработчики любят подшучивать над раздуванием зависимостей Javascript (и вполне имеют на это право, учитывая историю пакетов наподобие left-pad); при этом часто упоминаются пакеты is-even и is-odd. Поэтому я заинтересовался, кто же на самом деле их использует?

Читать далее
Total votes 28: ↑27 and ↓1 +26
Comments 18

Как работают трансформеры: разбираем математику

Level of difficulty Medium
Reading time 28 min
Views 16K

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

Как вы увидите, математика модели не так уж сложна. Сложность возникает из-за количества этапов и количества параметров. Перед прочтением этой статьи я рекомендую прочитать пост Illustrated Transformer (или читать их параллельно) [перевод на Хабре]. Это отличный пост, объясняющий модель трансформера интуитивным (и наглядным!) образом, поэтому я не буду объяснять то, что уже объяснено в нём. Моя цель заключается в том, чтобы объяснить, как работает модель трансформера, а не что это такое. Если вы хотите углубиться в подробности, то изучите известную статью Attention is all you need [перевод на Хабре: первая и вторая части].

Читать далее
Total votes 40: ↑40 and ↓0 +40
Comments 8

Сжимаем текст в изображения PNG

Level of difficulty Easy
Reading time 2 min
Views 5.7K

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

Текст шекспировской трагедии «Ромео и Джульетта» состоит примерно из 146 тысяч символов. Благодаря английскому алфавиту каждый символ можно описать одним байтом. Так что размер текстового файла в обычном Unicode составляет примерно 142 КБ.

В статье Adventures With Compression её автор JamesG размышляет о соревнованиях по сжатию текста и предлагает интересную мысль...

Читать далее
Total votes 19: ↑17 and ↓2 +15
Comments 38

Я разработчик, а не компилятор

Level of difficulty Easy
Reading time 3 min
Views 52K

Недавно у меня было телефонное собеседование, на котором мне задавали разнообразные вопросы по Java. Это стандартное собеседование, и большинство вопросов тоже было вполне стандартным:

Что такое полиморфизм?

В чём разница между List и Set? Когда стоит использовать первое, а когда второе?

Где можно столкнуться со взаимной блокировкой (deadlock)?

В чём разница между строгой и слабой типизацией?

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

Читать далее
Total votes 145: ↑136 and ↓9 +127
Comments 201

Быстрый парсинг 8-битных целых чисел

Level of difficulty Easy
Reading time 6 min
Views 10K

Допустим, вам нужно быстро распарсить 8-битные целые числа (0, 1, 2, …, 254, 255) из строки ASCII/UTF-8. Задача взята из проекта simdzone под руководством Йероена Коеккоека (NLnet Labs). Дана строка и её длина: например, ’22’ и длина 2. Наивное решение на C может выглядеть так:

Читать далее
Total votes 31: ↑31 and ↓0 +31
Comments 21

Information

Rating
Does not participate
Location
Россия
Registered
Activity