Подписка на блог

В Телеграме помимо ссылок на заметки делюсь околодизайнерскими наблюдениями.

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

В Тумблере и Же-же есть автоматические трансляции. Если не работает, напишите мне: ilyabirman@ilyabirman.ru.

По РСС и Джейсон-фиду трансляции для автоматических читалок

Программирование

Проверка непустоты текста в ПХП: программисты пишут

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

Напомню, я предложил проверять так:

if ((string) @$text !== '') { ... }

Мне понесли варианты. «Специально для этого есть функция empty ()»:

1

if (!empty ($text)) { ... }

Это код с ошибкой: для (int) 0 проверка будет пройдена.

2

if (trim ($text) !== '') { ... }

Это код с двумя ошибками: если переменная $text не определена, выведется предупреждение; если текст состоит из пробелов, проверка не будет пройдена.

3

if (isset ($text) && trim ($text)) { ... }

В этом коде исправлена только первая ошибка предыдущего.

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

4

if (isset ($text) && ($text !== "")) { ... }

Это длинный и мусорный код, и снова с ошибкой: и для false, и для NULL проверка будет пройдена.

5

if (isset ($text) && (string) $text !== '') { ... }

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

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

6

Все варианты кода с оператором ?? — с фатальной ошибкой: такого оператора нет в ПХП 5.4, на котором должна работать Эгея.

7

if (@strlen ($text)) { ... }

Этот код работает правильно.

Неприятность в том, что глядя на него нельзя этого сказать с уверенностью. Нужно читать документацию. Оказывается, у strlen () есть полезная особенность: если передать ему массив, он вернёт 0, а вовсе не 5 ("Array"). Правда, это только начиная с ПХП 5.2, хе-хе. В документации не сказано, как он ведёт с себя с переменными других типов, поэтому нужно идти дальше и читать документацию по неявному преобразованию типов, чтобы узнать, что strlen (0) вернёт 1, как мне и требуется. Полагаться на такие штуки, когда ожидаешь какого-то чёткого и тонкого поведения, как-то некомфортно.

Поэтому я пока оставил свой вариант, забив на потенциальную проблему с "Array".

 13 комментариев    1549   3 мес   программирование   ПХП

Проверка непустоты текста в ПХП

Только не бомбите, я для себя.

В ПХП оператор == проверяет равенство значений безотносительно типа. Поэтому строка «42» и число 42 с его точки зрения равны.

Это удобно: в большинстве случаев не нужно вообще думать о типах, просто сорок два равно сорока двум. Аналогично равны, например и логическая истина и число 1. Когда важно, чтобы значения были не просто равны, но ещё и совпадали по типу, используется оператор строгого равенства === .

Часто важно убедиться, что переменная не пуста. Можно проверить так:

if (@$text) { ... }

Как бы «если текст есть, то». Любая непустая строка приведётся к логически истине, при этом и пустая строка, и null, и даже неопределённая переменная приведутся ко лжи, и условие не выполнится.

Но есть нюанс. Число 0 тоже приводится к логической лжи. С этим был связан баг в Эгее: если текст заметки состоят целиком из нуля, заметку не получалось сохранить, потому что до одной из таких строчек этот текст доходил в виде числа, и условие не выполнялось. А это вполне легальный текст заметки.

У меня рука не поднимется исправить так:

if (@$text or $text === 0) { ... }

Поэтому теперь я проверяю наличие текста так:

if ((string) @$text !== '') { ... }

Не так элегантно, как было, но вроде жить можно. Или нет?

Продолжение

 14 комментариев    1735   4 мес   вопрос   программирование   ПХП

Шорткаты на Айфоне

Пардон, это заметка типа «поток сознания». Макс, не читай.

В 12-м Ай-ОСе появилось приложение Шорткаты. На самом деле это Эплы купили давно существовавшее приложение Воркфлоу и переименовали его, но не суть. Типа ура, пришла автоматизация в Ай-ОС, можно научить телефон чему-то умному!

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

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

Я прочитал штук пять статей разных авторов про то, как они классно используют Шорткаты, и на каждый их пример мне оставалось только пожать плечами. Они все какие-то вымышленные, таких задач не бывает в моей жизни. Например, один автор, уезжая с работы, запускает шорткат, который смотрит, сколько ему ехать до дома с учётом пробок, и отправляет жене эсемеску «милая, я буду через %t». Надеюсь, его жена настроила автоответ «жду, любимый!», и вся эта коммуникация не доставляет никаких хлопот обоим.

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

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

Они добавили экшен в «Шорткаты»! Как, почему? В итоге этой фичей смогут воспользоваться в лучшем случае один процент из тех, кому она понадобится. Точнее, даже из того одного гипотетического процента, кто это найдёт, большинство не смогут составить сам шорткат. Дело в том, что экшен Get Current Song нужно ещё пропустить через экшен с феноменально бессмысленным названием Text, и только потом копировать в буфер. В результате у меня есть вот такой шорткат:

То есть как программист ты можешь догадаться, что, видимо, Get Current Song возвращает объект, у которого несколько полей, и который не умеет автоматически преобразовываться в тип string, а Copy To Clipboard ожидает на входе именно этот тип, и поэтому нужно строку составить вручную из полей объекта. Но как до этого должен догадаться обычный человек я не понимаю. Зато я отлично понимаю, как эта фигня озадачит даже программиста.

Вот как то же самое выглядело бы в коде (язык вымышленный):

Let s = Music: GetCurrentSong
CopyToClipboard s.Artist ": " s.Title

Как этот текст может быть менее понятен, чем та хрень, которая у меня на скриншоте? Экшен Text даже не глаголом называется! Что такое Local Only я не представляю. В программировании есть хотя бы документация по функциям, а тут нет нихрена. Это похоже на паззл.

В общем, однажды мне пришло в голову, как использовать шорткаты. Так устроена моя банковская жизнь, что часть месяца мне выгоднее рассчитываться одной карточкой, а вторую часть — другой. А чтобы переключить дефолтную карточку в Эпл-пее, нужно идти в какие-то адские дебри настройки. И я подумал: «О! Сделаю себе шорткат, который будет по команде включать нужную карточку. Пусть сам идёт в нужные дебри настройки и жмёт нужные кнопки!» Это-то должно быть возможно?

Хрен. Оказалось, что нельзя сделать шорткат, который меняет что-то в настройке.

И вот тогда я подумал, что надо будет написать этот пост и объявить «Шорткаты» полностью бесполезным говном.

Но как раз в это время я засобирался к родителям на дачу; — и тут в истории наступает неожиданный поворот (оцените также невероятную пунктуацию в этом предложении).

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

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

И аналогичный для отъезда. Даже в Сири добавил. Теперь говорю: «Сири, нагрей дачу!» и она греет. Это круто. Что такое Show When Run я, разумеется, не знаю.

Зацените ещё, как совершенно бесчеловечные смс-команды завёрнуты в красивые прямоугольнички с тенями! Вот оно, программирование будущего по версии Эпла.

Конечно, из-за того, что вместо нормального кода я должен составлять это из тупых блоков, эта штука совершенно неповоротлива. Скажем, я рассказал про эту штуку папе — он порадовался, попросил меня скинуть экшен ему. Ну я разобрался, как это сделать (конечно, просто скопировать код и вставить в чат в телеграме я не могу). И что толку? У папы он не заработал, потому что у него в Контактах дачная симка называется не так, как у меня, а отредактировать он ничего не может. Почему эти экшены добавились как нередактируемые, я понятия не имею.

А вот как это могло бы выглядеть, если бы это был код:

Messages: Send "Temp.R1=+20 XXXXX" To "Dacha Uvildy Ksytal"
Messages: Send "Temp.R2=+20 XXXXX" To "Dacha Uvildy Ksytal"
Messages: Send "Temp.R3=+20 XXXXX" To "Dacha Uvildy Ksytal"

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

 13 комментариев    3120   9 мес   жизнь   программирование   Эпл

Что посмотреть с ВВДЦ 2016—2018

Я собирался опубликовать заметку о ВВДЦ—2016 два года назад, но забыл. Я собирался опубликовать заметку о ВВДЦ—2017 год назад, но поленился. А теперь уже прошло ВВДЦ—2018, так что опубликую всё вместе. Если вам влом читать длинную заметку, то посмотрите хотя бы доклад 803 с ВВДЦ-2018, про анимации на десятом Айфоне.

Начнём с того, что ВВДЦ — недельная эпловская конференция, а не только доклад о новых продуктах, с которого она начинается. Кроме этого главного доклада (Keynote) там проходят ещё десятки других докладов о технологиях, дизайне, маркетинге и чёрт знает чём ещё. Поэтому после завершения недели ВВДЦ имеет смысл поставить приложение ВВДЦ из Апстора и посмотреть видосы всего, что покажется интересным.

Обязательная программа

На любой ВВДЦ я обязательно сначала смотрю вот эти доклады, которые проходят каждый год. Здесь ссылки ведут на 2018:

101. Keynote. Это то, что смотрят все. Тим Кук, анонсы для журналистов, все дела.

102. Platforms State of the Union. Это такой продвинутый кейноут. Тут рассказывают о том, какие новые фичи для разработчиков появились на всех платформах и как прикрутить к своим приложениям те новые штуки, о которых рассказали в главном докладе. В некоторых старых ВВДЦ это ещё называлось Platforms Kickoff.

209. What’s New in Cocoa for macOS. Раньше это просто называлось What’s New in Cocoa. Детально про всё новое в Макосе. В прошлом году из этого я узнал, что в Хай-Сьерре дали пользователю перетаскивать несистемные элементы правой стороны меню. В этом году было интересно про новый тёмный режим, который появится в Мохаве.

202. What’s New in Cocoa Touch. В этом году важно про Siri shortcuts. А вообще это про всё новое в Ай-ОСе.

Если вы разрабатываете для часов или ТВ, имеет смысл так же смотреть сессии What’s New про эти платформы.

ВВДЦ—2016

Самое интересное для меня:

403. Swift API Design Guidelines. The Grand Renaming. Это самая клёвая сессия, про дизайн АПИ:

712. Working with Wide Color. Посмотрел, чтобы быть лучше готовым к светлому будущему, когда основы перевернутся и в вебе тоже. Сколько же всего приходится взорвать в системе, чтобы поддержать другую цветовую модель!

701. Introducing Apple File System. A snapshot of the next generation in storage. Давно жду новую файловую систему, поэтому было интересно. Снэпшоты кайф, должны сильно улучшить тайм-машину, а ещё, вероятно, сделают возможным лёгкую реализацию многопользовательскости на айпадах.

Ещё разное:
208. What’s New in watchOS 3. Много интересного про дизайн и для дизайнеров. Порадовала идея вместо прогрессбара («делаем...») показывать галочку («задание принято!»), чтобы дать человеку спокойно опустить руку. Я потом про это рассказывал в каких-то своих докладах про обратную связь.

217. Introducing SiriKit. Hey Siri, say hello to apps. Было интересно, как оно спроектировано. Плата за простоту подключения — негибкость. Ни к Ангстрему, ни к Правилам русского языка, например, не прикрутить.

705. How iOS Security Really Works. Интересно для общего развития. Чувак порадовал: «Злоумышленники устанавливают на ваши телефоны кейлоггеры, шпионские программы, неотключаемую рекламу. Откуда мы это знаем? Мы это видим на других платформах».

ВВДЦ—2017

Самый запомнившийся доклад:

803. Designing Sound. Очень клёво! Чувак играет на живых инструментах рингтоны Айфона. Самый любимый момент — про звук уведомлений на часах:

Остальное:
823. Designing Glyphs.

802. Essential Design Principles. Ну прям почти по темам моей интерфейсной книги, начиная с человечности. Потом говорит о взгляде новичка, обратной связи, visibility (у нас более глубокая тема «Информативность»), consistency (у нас есть темы «Последовательное волшебство» и «Привычка»), теория близости и группировка (у нас это одна тема). Порядок, в котором он говорит о принципах, довольно случайный, а примеры — суперабстрактные. Лучше приходите на мой курс или подписывайтесь на книгу!

503. Introducing HEIF and HEVC. Подробно про новые форматы видео и картинок: почему они лучше, как система их поддерживает, как обеспечивается совместимость. Интересно для общего развития.

301. Introducing the New App Store. Подробно про большой редизайн Апстора.

715. What’s New in Apple File System. Как эплы незаметно и без проблем заменили файловую систему миллионов дивайсов.

815. How to Pick a Custom Font.

ВВДЦ—2018

Самое классное не про дизайн:
223. Embracing Algorithms. Очень понравилось. Обязательно смотреть всем программистам. Мне в работе, к сожалению, иногда попадались программисты, которые не хотели искать красивое решение задачи, разбираться в математике и физике, оптимизировать. Хотя ведь это и есть работа программиста, и если ему это не в кайф, то непонятно, что он делает в этой профессии.

703. Introducing Create ML. Как можно использовать машинное обучение в ваших программах. Рекомендую дизайнерам смотреть, чтобы понимать, что, оказывается, уже можно довольно легко делать, вовсе не будучи Гуглем или Яндексом (классифицировать фоточки и текст, например).

Самое классное про дизайн:
803. Designing Fluid Interfaces. Докладывает чувак, который дизайнил анимации для 10-го айфона. Разбирает по косточкам, показывает в слоумо. Когда я купил десятку, я сам очень долго пытался разобраться в том, что там происходит, а тут супернаглядно. Просто кадр:

801. The Qualities of Great Design. Интересно про самое понятие «качество» и про то, почему мы ценим качественное. А отдельно интересна сама форма доклада: девушка назадавала вопросов коллегам, ставит аудиофрагменты их ответов и комментирует. Зачем-то поставила два пробела между словами:

210. Introducing Dark Mode. Всё про новый тёмный режим: как подбираются цвета, как рисуются темы, как адаптируются иконки. Тёмный режим — это не просто инверсия светлого, там вообще всё по-другому.

218. Advanced Dark Mode. Более задротская версия предудыщего доклада.

Остальное:
239. Designing Web Content for watchOS. Вотч-ОС 5 научится показывать веб-странички на часах. Короткое видео о том, как к этому подготовиться.

804. The Life of a Button. Довольно занудный доклад про то, о чём нужно думать, когда дизайнишь кнопку. Но правда в том, что обо всём этом действительно нужно подумать.

811. Presenting Design Work.

233. Adding Delight to your iOS App. Не рекомендую. Добавил в список, потому что вас, как меня, могло подкупить название. Я ожидал, что там будет что-нибудь про клёвые анимации или звуки. А там про какие-то фичи типа использования внешнего экрана по Эйрплею. Лучше смотреть 803, короче.

713. Introducing Natural Language Framework. Можно научить программу понимать разное про текст: тему, настроение, упомянутые объекты и всё такое.

См. также заметку о докладе с ВВДЦ-2015 о новых системных шрифтах.

 Нет комментариев    1330   2018   ай-разработка   программирование   Эпл

Кнопка «ОК»

Тёма пишет:

Больше всего мне в почте не хватает кнопки «ок», которая бы отсылала в ответ на письмо сообщение «ок».

Что может быть проще? Запускаем привычным движением редактор скриптов:

Пишем скрипт:

tell application "Mail"
	
	activate
	set the_selection to the selection
	set the_message to item 1 of the_selection
	set the_reply to reply the_message
	tell application "System Events"
		keystroke "OK."
		key code 36
		key code 36
	end tell
	send the_reply
	move the_message to mailbox "[Gmail]/All Mail" in account "Gmail"
	
end tell

Редактируем по вкусу, сохраняем в ~/Library/Scripts/Applications/Mail.

Убеждаемся, что у нас включено меню скриптов:

Ну и всё, теперь когда почтовик в фокусе, в меню скриптов есть пункт Reply OK, который делает то, что нужно. Навесить шорткат на него — дело техники.

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

См. также другие заметки в таком духе:

 1 комментарий    2244   2018   лайфхак   программирование   эл. почта

Что почитать на выходных — 165

Вот:

  1. Designing Hebrew Type.
  2. Reachability by overscrolling. Написал в английском блоге о том, как делать интерфейс для Айфона ещё лучше.
  3. Software 2.0. Нейросети — это не просто ещё один инструмент в арсенале программиста, а вообще другой вид софта.
  4. Как объяснить дедушке веб-аналитику за 5 минут с картинками.
  5. «Я вижу в сети много эмоциональных комментариев на мою критику экономической программы Навального». Андрей Мовчан сильно про Навального.

Хотите стать спонсором рубрики? Пишите: ilyabirman@ilyabirman.ru

Как сделать окно браузера нужного размера?

Когда я написал про окно Бирмана, у меня спросили, как я делаю окно браузера ровно 1024 в ширину. Разумеется, встроенными средствами компьютера. Я просто захожу в меню скриптов и нажимаю там нужный пункт:

Как сделать окно браузера нужного размера?

Но откуда у меня взялось это меню вместе с пунктами? Я просто написал скрипты. Запускаете редактор скриптов:

Как сделать окно браузера нужного размера?

Пишете в нём что-нибудь в таком духе:

tell application "System Events"
	set frontMostApp to (name of first process where frontmost is true)
end tell

tell application frontMostApp
	set allWindows to (every window where visible is true)	
	set frontWindow to item 1 of allWindows
	tell frontWindow
		set bounds to {0, 21, 1024, 1557}
	end tell
end tell

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

Как сделать окно браузера нужного размера?

Заходите в это меню, жмёте Open Scripts Folder → Open User Scripts Folder. Перемещаете свой файл скрипта в эту папку — и всё, этот скрипт показывается в меню.

Таким образом можно делать любые скрипты для любых приложений, например у меня несколько полезных для Айтюнса написано:

Как сделать окно браузера нужного размера?

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

 289   2017   Айтюнс   браузеры   лайфхак   программирование   Сафари   Эпл

ПХПШторм и рефакторинг при переименовании файла

В заметке о ВС Коде я написал:

Однажды я видел, как разработчик переименовывал файл в «ПХПШторме». На экране несколько секунд заполнялся прогрессбар. Нет, спасибо.

Мне написал Александр Яскевич:

То, что ты видел — рефакторинг. Если на этот файл в проекте были ссылки, ПХПШторм их также менял в то время, пока ты наблюдал прогрессбар. Ну или просто искал. Даже если ничего не нашел, время на поиск тратится. В таких мелочах ИДЕ от редактора и отличается.

Я в курсе, что это рефакторинг. Тут есть две проблемы.

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

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

 16   2017   программирование

Как прикрутить поисковый движок «Роза»

Я уже рассказывал, что в новой Эгее 2.6 — новый поисковый движок «Роза» Романа Парпалака. На примере Эгеи расскажу немного о том, как вы можете использовать его в своих продуктах.

Что делает Роза

Роза — движок поиска по переданным ему данным.

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

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

Таким образом, поиск — это взаимная работа клиента и Розы. Прикрутить её сложнее, чем использовать движок поиска общего назначения. Зато понимание структуры данных позволяет гибко форматировать результаты и учитывать их природу при ранжировании.

Любой приличной заметке в современном интернете нужна картинка. Поэтому пусть здесь будет скриншот, иллюстрирующий покрытие Розы автоматизированными тестами:

Как прикрутить поисковый движок «Роза»

Теперь к делу.

Хранилище

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

function e2_rose_storage () {
  static $pdostorage = null;

  if ($pdostorage === null) {
    $pdo = new \PDO (
      'mysql:'.
      'host='. $_db_server .';'.
      'dbname='. $_db_name. ';'.
      'charset=utf8',
      $_db_user,
      $_db_password,
    );
    $pdo -> setAttribute (\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
    $pdostorage = new PdoStorage ($pdo);
  }

  return $pdostorage;
}

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

Индексация

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

$stemmer = new PorterStemmerRussian ();
$indexer = new Indexer (e2_rose_storage (), $stemmer);
$indexable = new Indexable (
  $_note_id,
  $_note_title,
  $_note_text
);
$indexer -> index ($indexable);

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

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

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

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

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

Но при обновлении Эгеи со старой версии, мне нужно аккуратно проиндексировать все написанные ранее заметки. В случае с моим блогом это около четырёх тысяч заметок. Поэтому просто запустить их индексацию в цикле нельзя: даже если операция уложится во временной лимит ПХП, всё это время пользователь будет думать, что сайт не отвечает. А если не уложится, то пользователь вообще ничего не увидит. Как обеспечить безболезненную фоновую индексацию — тема отдельной заметки, но важно, что это забота клиента, а не Розы.

Когда пользователь удаляет или отзывает заметку, я делаю примерно так:

$stemmer = new PorterStemmerRussian ();
$indexer = new Indexer (e2_rose_storage (), $stemmer);
return $indexer -> removeById ($_note_id);

Поиск

Чтобы искать, нам понадобится файндер (а ему понадобится стеммер):

$stemmer = new PorterStemmerRussian ();
$finder = new Finder (e2_rose_storage (), $stemmer);
$finder -> setHighlightTemplate (
  '<span class="'.CSS_CLASS_HIGHLIGHT.'">%s</span>'
);

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

Теперь можно сделать запрос и достать результаты поиска:

$rose_query = new Query ($query);
$rose_query -> setLimit (SEARCH_LIMIT); 
$resultSet = $finder -> find ($rose_query);

Тут я не могу продолжать как ни в чём не бывало и не сделать ремарку. Объекто-ориентированное программирование делает мне больно. Просто так написать нельзя:

$results = rose_find ($db_link, $query, SEARCH_LIMIT);

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

Итак, после того, как мы получили $resultSet, мы уже можем выводить результаты. Но это тот момент, когда можно попросить Розу подкрутить релевантность, что я и делаю:

foreach ($resultSet -> getFoundExternalIds () as $external_id) {
  $note_id = e2_note_id_from_rose_id ($external_id);
  $note_rec = e2_note_by_id ($note_id);
  if ($note_rec['IsFavourite']) {
    $resultSet->setRelevanceRatio ($external_id, 2);
  }
}

Так я поднимаю избранные заметки повыше.

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

$snippetBuilder = new SnippetBuilder ($stemmer);
$snippetBuilder -> setSnippetLineSeparator(' · ');
$snippetBuilder -> attachSnippets ($resultSet, function (array $external_ids) {
  $result = array ();
  foreach ($external_ids as $external_id) {
    $note_id = e2_note_id_from_rose_id ($external_id);
    $note_rec = e2_note_by_id ($note_id);
    $note_pack = e2_package_note ($note_rec);
    $result[$external_id] = $note_pack['text'];
  }
  return $result;
});

Чтобы собрать сниппеты, Розе нужны полные тексты заметок — сама она их не хранит, а о структуре моей базы данных ничего не знает. Поэтому в метод attachSnippets мы тут передаём колбек, который Роза вызывает, чтобы их получить. Он, как видите, вытаскивает заметки из базы.

После этого можно собрать результаты:

foreach ($resultSet -> getItems () as $external_id => $item) {
  $note_id = e2_note_id_from_rose_id ($external_id);
  $note_rec = e2_note_by_id ($note_id);
  $note_pack = e2_package_note ($note_rec);
  $note_pack['title' ] = $item -> getHighlightedTitle ($stemmer);
  $note_pack['text' ] = '<p>'. $item -> getSnippet () .'</p>';
  $note_packs_found[] = $note_packs;
}

Я подсвечиваю найденные слова в заголовке и показываю сниппет вместо текста заметки.

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

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

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

 675   2017   веб-разработка   программирование   Эгея

ВС Код

Это сумбурный пост, потому что редактировать его мне некогда.

Я много лет использовал редактор кода «Сублайм-текст». Он не дотягивал по функциональности даже до «Эдитплюса», которым я пользовался на Винде больше десяти лет назад, но казался мне самым приятным и продвинутым из того, что есть на Маке. Всякие ИДЕ я не рассматривал — они уродские и тормозные. Однажды я видел, как разработчик переименовывал файл в «ПХПШторме». На экране несколько секунд заполнялся прогрессбар. Нет, спасибо.

Но месяц назад я нашёл «ВС Код». Кажется, это лучшее, что сделал Микрософт. Он устроен как идеальное ИДЕ: ИДЕ нет, а функция выполняется.

ВС Код

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

Зачем разная расцветка разным проектам? Например, мне нравится, что я просто узнаю по палитре, что передо мной: мой сайт, советы или Эгея.

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

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

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

ВС Код

Она вытянула блейм из гита и документацию по функции ПХП. Самое крутое, что чтобы это было, я не ничего не делал — оно как-то само. Или, может, это плагин GitLens, который я тоже установил? В любом случае, я даже не заметил.

Можно считать это главной радостью ВС Кода: он просто врубается, как у тебя что устроено, что у тебя там есть, и заставляет это всё работать. Есть, например, ещё встроенная фича Tasks, которая сама находит твои package.json и gulpfile.js и тоже заставляет их работать без настройки. Тут, правда, сначала её надо один раз попросить включиться. Надеюсь, они додумаются в будущих версиях сделать это также прозрачно, как гит.

Кстати, лайфхак: я настроил пять боковых панелей (файлы, гит, поиск, отладка и расширения) на ⌘1...⌘5. Это стандартные для Мака сочетания для переключения между разными видами. Надо ведь постоянно переключаться между файлами и гитом.

Есть всякие мелкие недостатки, конечно, в том числе по сравнению с Сублаймом, но в целом — кайф.

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

 164   2017   программирование   софт
Ранее Ctrl + ↓