Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS · 📢 Канал в Telegram @stendap_sogodni
29.03.2023
Абсолютний мінімум самоменеджменту
Сьогодні був цікавий день; я ревьював 380 пул реквестів. Це через те, що більш як місяць тому припинив це робити, бо сфокусувався на іншій роботі. З одного боку, нікому так не раджу робити. З іншого, радий що все ж таки все продивився, та що тепер можу повернутись до щоденного режиму.
Щоб продовжити вчорашню тему про керування часом, думав над абсолютно необхідним мінімумом, який треба собі забезпечити — не заради якоїсь “продуктивності”, а просто щоб не жити в “режимі білочки”, тобто не стрибати без кінця від одного негайного діла до іншого.
-
Відокремлення “вхідного кошика” та його регулярне опрацьовування. Вхідний кошик — то місце для всього нового. Головна причина цьому: більшість “нового” це інформаційне сміття. Щоб не жити у смітті, потрібно свідомо виділяти те, що потребує уваги, та позбавлятись всього іншого.
-
Система виконання (а також сортування за пріоритетом та, можливо, планування.) Найпростіша то є список задач (або голова). Всього відразу не зробиш. Система виконання тримає все, що треба зробити, та — головне! - дає гарантію, що воно буде зроблене. (Або свідомо відкинуте.) Без такої системи все навколо починає нагадувати про задачі, і все одно багато забувається.
-
Календар потрібний для відстеження подій, запланованих на дату та час. До того сучасний календар підтримує звʼязок зі співучасниками. Напевно, тому з календарем зазвичай у всіх все добре - діє соціальний тиск. Тільки додам, що календар не є системою виконання; в першу чергу, тому, що це місце для подій, що відбудуться точно та в певний час, а задачі не відбудуться, поки ми їх не зробимо.
-
База знань зберігає все, що не є задачею або подією. Головна функція такої бази — це звалище всього, що нам зараз не потрібно, а потім, може, ще й згодиться. База знань звільняє свідомість та робочий простір.
PS: 🧑🎨 Unsplash не оцінив мої вертикальні шпалери, тож доведеться шукати інший фотохостинг. Та ще такий, щоб було відомо, що на ньому такі шпалери шукають.
28.03.2023
Bullet journal: постмортем
Настав час для новин по самоменеджменту з блокнотом. Що ж, система вмерла — десь на кінець другого місяця, хоча здригалася ще до середини березня. Робимо постмортем.
-
Що працює добре. Блокнот; кому як, а мені приємно писати ручкою (лінером) по паперу. Регулярна обробка вхідних куп (пошти, нотаток тощо) - без цього я взагалі гублюсь. Але… задачі з вхідних куп треба заносити в список задач. Якому ти довіряєш. На цьому й починаються проблеми.
-
Причина смерті — задач стало надто багато. До речі, окрім задач на день я ще вів окремий перелік проєктів а-ля GTD - туди потрапляло все, що за один підхід не зробиш. Довгий час задачі, записані на день, виконати виходило, а копати список проєктів — ні. Потім й на день стало кілька десятків задач. Спостерігаю, що в мене задач завжди стане більше, ніж я фізично можу виконати.
-
Минулого тижня слухав книжку Four thousand weeks: Time management for mortals. Вона як раз про те, що сучасне життя вимагає надто багато — більше ніж реально зробити — тому спроба все встигнути чи побудувати систему, яка це допоможе зробити — даремна. Натомість книжка радить усвідомити, що час обмежений, та фокусуватись на тому, що ти можеш зробити, а не на ідеалістичному списку задач.
-
На цей час спробую використати систему Final Version Perfected. Її сила як раз в тому, що вона здатна працювати з необмеженим списком задач; найменш важливі з них просто залишаються незробленими та з часом їх викреслюють. Тобто визначення пріоритетів та виконання поєднані в один процес. Та, головне, немає тяжкого для мене аспекту відмови від чогось; навпаки, в системі FVP ти обираєш, яку справу зробиш наступною, надаєш їй ваги, а це важливо для позитивного сприйняття всієї системи.
27.03.2023
Паралелізація запитів в Ruby
Хочу висловити похвалу моделі одночасного виконання в Ruby, а саме, класу Thread. Ruby так зневажливо відносять до повільних мов, що яка вже там одночасність! Тут же ж навіть багатопотоковості немає. (До речі, справжня багатоядерна паралелізація в Ruby 3 теж вже є, з класом Ractor).
Насправді є сценарій, в якому одночасне виконання дуже допомагає, та він всім нам добре відомий — це звертання до мережевих ресурсів. Будь то запити до API, чи завантаження сторінок, чи надсилання листів по SMTP - всілякі операції через Інтернет можна робити паралельно в декількох потоках, бо під час запиту програма все одно стоїть та чекає відповіді. (Єдине, що треба мати на увазі — не робіть з потоків звертань до бази даних, бо це вичерпає пул підключень. Або пул треба збільшити, або роботу з базою винести з потоку.)
# Паралельне завантаження сторінок
urls.map { |url| Thread.new { Net::HTTP.get(url) } }.map(&:join)
Так на минулому тижні мені вдалося замінити процес, що займав дві години, та опитував кожний ресурс послідовно, на паралелізоване рішення, якому потрібно двадцять хвилин. І це мені поки боязно робити надто багато запитів — можливо, в майбутньому зробимо ще швидше.
Для більш поглибленого використання можливостей одночасності можу порадити гем concurrent-ruby. В ньому реалізовані класи для всього, що можна собі уявити. Я, наприклад. завжди маю на увазі пул тредів для обмеженої паралелізації.
26.03.2023
Structured Data та OpenGraph
Сьогодні черговий раз намагався щось зробити з SEO на сайті. Дізнався, що на цей час Google хоче бачити розмітку Structured Data, як головне джерело метаінформації про сторінки. Ніяк не допомагає те, що стандарт Structured Data визначає безліч атрибутів, та до того ж декілька різних типів сторінок.
До цього мені був відомий стандарт OpenGraph. Втім, ці два стандарти розв’язують різні задачі. OpenGraph призначений для створення деталізованих карточок для посилань в соціальних мережах т.і.; Structured Data збагачує зміст сторінки метаінформацією для спрощення машинної обробки. В цьому випадку, Structured Data допомагає Google будувати базу даних сторінок.
Одним словом, з минулого вересня рейтинги в Google так і не повернулись. Так, в січні 2020 на мій сайт було 2.5K переходів з Google, а цього місяця - 24; буквально в 100 разів менше.
PS: розпочав акаунт Unsplash зі шпалерами на iPhone. Має піти добре, бо відбір матеріалу відбувається напівавтоматично. Шпалери ці беруться з нової функції iOS 16 - Photo Shuffle. Вона сама обирає з моєї фотобібліотеки красиві світлини. Далі залишається тільки відбирати найкращі та поширювати через Unsplash.
25.03.2023
Cюжетні пазли - мало відомий піджанр детективних ігор
🕵️🧩🎮 Є такий мало відомий піджанр детективних ігор, я б назвав його “сюжетний пазл”. В таких іграх всі події сюжету вже відбулися в минулому, а нам залишається тільки розслідувати їх. Метою є зібрати з розрізнених шматочків певну картину подій. Це нагадує такі фільми, як Памʼятай або Підозрілі особи. Або процес пошуку помилки в логах. :)
Ось декілька “сюжетних пазлів”, які мені дуже сподобались. Одне в них погано — по другому разу проходити вже не цікаво.
Her Story - вся гра — це архів інтервʼю з дівчиною, який можна шукати за ключовими словами. Треба зрозуміти, що з нею сталося. Деякі ключові слова можна просто вгадати, а деякі доведеться виділяти з вже доступних оповідей. Найприємніше, коли помічаєш особливе слово, за яким розкривається відразу цілий шар небачених досі відео.
Return of the Obra Dinn - розгадай, як помер кожний член команди корабля-привида, та як їх звали. Причому вся інформація, яка є — це момент смерті для кожного знайденого (по черзі) тіла. Причину смерті здогадатись нескладно, а от де хто, доведеться розбиратись за неявними ознаками. Гра має унікальний графічний стиль та чудову озвучку.
Eternal Threads - треба побудувати (а точніше, відновити) дерево рішень, яке призведе до правильного результату. Причому це не так просто, як вибрати “правильне” рішення кожного разу! Бо треба ще обрати правильний момент, а також інколи “помилятись”, щоб вчитись на цих помилках. Та, звичайно, з кожним рішенням відкриваються або закриваються гілки дерева…
Ще у мене в списку бажань The Case of the Golden Idol та Telling Lies.
24.03.2023
Коли закладати локалізацію додатка?
Обговорення вчорашньої статті на DOU порушило цікаве питання. А саме, чи має локалізація додатка бути закладена на початку розробки? Я маю на увазі — чи треба від початку роботи складати рядки у словник та використати в коді ключі перекладу замість рядків без перекладу?
На моєму досвіді, щоб це мало сенс, треба дві умови. Перше — щоб інтерфейс додатка був чітко заданий заздалегідь. Якщо розробка має, так би мовити, характер Agile, та екрани змінюються з новими вимогами та випробуваннями, то ви змарнуєте купу часу на підтримку словника для фраз, які не попадуть до остаточної версії.
Друге — що багатомовність має бути обґрунтована потребами бізнесу. Та головне, що на перекладі додатка інтернаціоналізація тільки починається. Треба ще продавати його на різних ринках, робити розкрутку, рекламу, підтримку користувачів. Перекладати інформаційні матеріали, нарешті. Якщо бізнес не планує це робити, то можливість зміни мови в додатку має суто символічний характер.
Я вважаю, що такий збіг обставин трапляється рідко. Так, якщо робити сервіс мікрокредитів для європейського банку, то в них і дизайн готовий є, і перелік країн, де він буде представлений. В інших випадках раннє впровадження локалізації тільки вадить розробці. Як я показав, додати i18n пізніше — цілком реально, а якщо це так, то не бачу сенсу думати про інтернаціоналізацію раніше, ніж це буде потрібно.
Навіть при розробці нового функціоналу в додатку, що вже має i18n, я схиляюсь до того, щоб нові рядки локалізувати вже наприкінці іншої розробки. До того ж як я писав в статті, в деяких місцях i18n здатний суттєво ускладнити архітектуру. Доведеться думати не тільки про розвʼязання базових задач бізнесу, а ще й про те, як розвʼязок локалізувати. Як на мене, то простіше ці дві справи робити окремо.
23.03.2023
Поштовий заголовок Received
Продовжуючи серію про приколи електронної пошти, розповім про заголовок Received
.
Це один з тих заголовків, що виставляються поштовою інфраструктурою, а не клієнтом, тому звичайні відправники про нього знати не будуть. Хоча, якщо відправляєш напряму до отримувачів — листи без заголовка Received
мають високий ризик попасти в спам. На перший погляд, це дивно — хіба заголовок з назвою “Отримав” виставляє не отримувач? Чому відправник має про нього думати?
А от виходить, що Received
- це як штемпель поштового відділення (застаріла аналогія у вік Нової Пошти.) Кожний сервер, через який проходить лист, має додавати свій Received
, в якому відстежується шлях листа. Зазвичай листи від відправника не йдуть прямо до отримувача, а проходять через так званий message submission agent. Це як ваше поштове відділення. Він й має виставити перший заголовок Received
.
Для звичайних, людських листів MSA - це той поштовий сервіс, яким ти користуєшся - GMail, наприклад. А якщо вже відправляти пошту з додатка самотужки, без поштового сервісу, то треба не забути самому додати Received
, в якому, як мінімум, буде зазначена дата посилання:
Received: from myapp.io by mx.myapp.io; Thu, Mar 23 2023 23 11:27:16 GMT
Все це описано у RFC 822.Через такі особливості SMTP і варто доручити доставлення пошти спеціалізованому сервісу, такому як Mailtrap - нехай вони (тобто ми :) самі читають RFC.
Також сьогодні на DOU вийшла моя стаття про українізацію Сінтри. Частково я ділився деталями тут на каналі, ще минулого літа, але тепер можна прочитати все разом.
22.03.2023
Як довести думку через ланцюг міркувань
Як довести думку до аудиторії? Це може бути потрібно як коли даєш презентацію, так і повсякденно — коли треба пояснити колегам рішення чи ситуацію, яка склалась. Тобто навичка ця корисна до кожного, хто працює в команді.
Я використовую таку модель. Треба визначитись з кінцевою думкою. Потім взяти, явно чи не явно, базовий рівень знань аудиторії. А потім — побудувати ланцюжок думок, який починається з чогось загально доступного для аудиторії, та закінчується висновком.
Найскладніше в цьому процесі — це уникнути стрибків в міркуваннях. Це коли наступна думка не випливає з попередньої. Звичайна причина стрибків — наші переконання, часто приховані. Через ці переконання для нас все послідовно — переконання заповнюють розрив в логіці. Але аудиторію такий стрибок примушує самим шукати пояснення, що або відвертає увагу, або взагалі викликає недовіру до презентації.
Тому я багато разів проходжу по тексту та перевіряю — чи не пропустив я крок. Якщо знаходжу — намагаюсь розкрити свої переконання. Насправді може це і є найцікавіше в презентаціях — досвід. з якого автор має ту чи іншу думку.
Як приклад, моя презентація про підхід React виросла навіть не з думки, а з почуття, яке раніше було описане в статті. Але щоб це почуття викласти, довелося довго копатися у своїх попередніх досвідах розробки, та в першу чергу для себе його зрозуміти. (Ось слайди, до речі.)
Буває й так, що ланцюжок ніяк не будується. Тоді доводиться починати спочатку. Або навіть передивитись свою кінцеву думку, бо вона виявилась хибною чи необґрунтованою — таке теж трапляється.
20.03.2023
Складнощі з міграціями в Redshift
Найбільш за все у схемі перетворення даних розрізами в Redshift мене дратує, що зміни структури бази ускладнюються суттєво.
В Redshift обмежені можливі зміни стовпчиків. Навіть така незавадна зміна, як з NOT NULL на NULL, не дозволена. Можна тільки додати новий стовпчик з потрібним типом та перенести туди дані. На щастя, стовпчики можна перейменувати, тому принаймні можна замінити старий стовпчик на новий. Поки в нас не було розрізів, все було більш-менш прийнятне.
Але якщо від стовпчика залежить розріз, то такий трюк не вийде. Тоді залишається тільки видалити розріз, змігрувати таблицю, та створити розріз наново. (А якщо розрізів багато… Доведеться перестворювати всі.)
Але так теж не вийде, якщо розріз вже активно використовується. Хоча б тому, що перше створення розрізу може зайняти багато часу — часу простою. Тоді доведеться створити новий розріз, може, з версією - my_stats_v2_mv
, наповнити його даними, та потім плавно перевести код зі старого на новий розріз. Перейменувати розріз не дозволено, тож він назавжди залишиться з версією в назві. Тобто з часом буде і v3_mv
, і так далі, на кожну необхідну зміну.
Добре, що всі ці складнощі можна частково приховати за красивим кодом з боку додатка. Є навіть гем Scenic, який вміє версіонувати розрізи. Тільки Redshift він не підтримує.
19.03.2023
Форми в React
Сьогодні, нарешті, повернувся до Сінтри, на яку останніми місяцями ніяк не вистачає часу. Працюю над декількома складними формами.
Для створення форм у React я беру react-final-form. (Є ще formik, який дуже схожий за використанням.) Головне що така бібліотека заміняє купу копіпасти, яка потрібна для керування станом полів окремо. Але взагалі, абстракція форми в React та в HTML трохи різна, та якщо це розуміти, форми покриють ще більше потреб.
Чого точно не треба робити, це зберігати стан форм в Redux. Будь-яка зміна стану Redux призводить до виклику кожного селектора в додатку. Тільки так Redux може визначити, які компоненти потребують перемальовування. Відповідно, якщо на кожний символ, введений в форму, міняти стан Redux, то втрата швидкодії забезпечена та залежить тільки від розміру додатка. Причому це фундаментальна проблема Redux; ніколи не кладіть в Redux те, що змінюється щосекунди або частіше. Прощавайте, фантазії про “чисту архітектуру”. (До речі, дуже ціню, що React Final Form дозволяє звузити підписку на зміни, та уникнути зайвої перемальовки. Так мені вдалося зробити навіть маленький табличний редактор, цілком на можливостях бібліотеки.)
Тоді виходить, що бібліотека react-final-form - це, в першу чергу, механізм збереження стану. Стан цей тимчасовий, та існує від початку змін до збереження їх в стале сховище. Це не завжди короткий проміжок; наприклад, в Сінтрі весь майстер створення бюджету з чотирма сторінками — єдина величезна форма. Так ми легко маємо доступ до будь-якого поля з будь-якого місця форми, а також можемо гортати майстер вперед та назад. Тільки коли ти натискаєш “Створити бюджет”, в базі даних створюються необхідні записи. До речі, щоб не втрати стан форми при перезавантаженні сторінки, дублюємо його в LocalStorage.
Одним слово, що я хочу сказати, що в React форма зовсім не має виглядати як форма, а натомість є абстракцією, яка спрощує керування тимчасовим станом деякого процесу.