Стендап Сьогодні
Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті
Підписатись на RSS
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
29.02.2024
Майже порожній аркуш
Широко відома проблема порожнього аркуша в дизайні інтерфейсів — тобто, що робити з застосунком за браком даних, на початку роботи. Проте, поки даних зовсім немає, зазвичай зрозуміло, чим їх замінити. Картинка з прикладом заповнення, відеопосібник, просто текст — за прикладами далеко ходити не треба.
Помітив, що існує й друга, більш підступна проблема. В деяких інтерфейсах одного чи двох початкових записів не вистачає для повноцінної роботи. Наприклад, я зіткнувся з цим у WeightPlot: щоб побудувати графік ваги, потрібно хоч тиждень даних. Але що показувати користувачу весь цей перший тиждень?
Проблема підступна, бо технічно, за рідкісним винятком, інтерфейс буде працювати навіть з одним записом (чого вже там, навіть з нулем записів все зазвичай технічно працює.) Також і тому, що розробка окремого дизайну, який буде видно перший тиждень, виглядає зайвою… Плюс, порожній аркуш — це просто заглушка, а от якщо якісь дані є, то вже доведеться придумати та розробити для них вигляд.
Окрім графиків, майже порожній аркуш впливає на сторінки зі статистикою, взаємовідносинами між записами, всілякими “розумними” інтерпретаціями. Для всього цього треба визначити мінімальний обсяг даних, з яким відображення має сенс. А далі… деколи навіть “зберіть більше даних, щоб побачити цю сторінку” буде краще, ніж нічого.
Я думаю, майже порожній аркуш необхідно врахувати, та навіть в першу чергу, бо саме його побачить новий користувач… і якщо досвід буде поганим, то він залишить продукт, не побачивши всю повноту та красоту наповненого даними інтерфейсу.
28.02.2024
Водяне охолодження — керування
🎛️ Як я згадував в пості про компоненти, в системи охолодження немає власного керування. Всі активні компоненти — помпа та вентилятори на радіаторі — керуються звичайним PWM з самого компʼютера.
Також немає датчиків температури води, які легко зʼєднати з компʼютером. Було б добре запобігати перегріву води — реальна можливість, якщо вентилятори недопрацьовують. Проте все ж головні показники, які ми будемо контролювати, це температура процесора та відеокарти.
Мета керування схожа на повітряне охолодження: збільшувати швидкість моторів відповідно до температури, щоб нічого не перегрівалось. Проте з повітрям ми зазвичай маємо один вентилятор на один датчик… а тут датчиків два. Якщо процесор або відеокарта нагріваються — маємо прискорити помпу. Такого мій BIOS робити не вміє — та й не знаю, який вміє, якщо врахувати, що датчик відеокарти знаходиться не на материнській платі.
Щоб розвʼязати цю головоломку, знайшов надзвичайну програму FanControl. Вона вміє встановити швидкість вентиляторів як функцію комбінації датчиків. Замість простої кривої, як в BIOS, тут справжній ЦОС. Єдине, що FanControl запускається вже з Windows, а до того в BIOS виставлено вмикати помпу на безпечно високу швидкість.
З таким рішенням компʼютер стабільно працює цілодобово та надійно та безшумно розганяється тоді, коли це потрібно. Дуже задоволений.
27.02.2024
Водяне охолодження — трубки
🚰 Якщо всі вище згадані компоненти відносно взаємозамінні у своєму класі та залишається тільки обрати ті, що подобаються, то на трубки залишається 80% архітектури.
Взагалі трубки є гнучкі та тверді. Гнучкі — з ПВХ, тверді — акрил чи ПЕТ. Чув, що варто брати спеціалізовані, бо звичайні трубки випускають в воду мікрочастинки, які зрештою забʼють радіатори, а це дуже неприємно. Плюс, трубки для водяного охолодження враховують нагрівання, під час до 50 градусів.
Окрім трубок, будуть потрібні ще фітинги, тобто металічні деталі. Кожне підключення потребує фітинга з різьбою — через них трубки підʼєднуються до компонент. Для гнучких та твердих трубок фітинги різні. А ще є ще крани, коліна, фільтри, системи швидкого розʼєднання тощо. Сюди можна непомітно ввалити купу грошей, бо один якісний фітинг коштуватиме від 4 доларів та до десятків. А потрібно їх багато.
…Іронія в тому, що насправді саме твердими трубками можна зробити більш тісну прокладку, бо гнучкі гнуться з величезним радіусом — сантиметрів з 20 мінімум — а з меншим складаються навпіл. Тверді теж можна гнути, тількі для того потрібний інструмент — або зʼєднувати колінами. Зате гнучкі набагато простіше у роботі, а у вузькому місці можна допомогти коліном чи відрізком твердої трубки.
За моїм досвідом, саме проєктування трубок та фітингів доведеться робити довго та ретельно. А з іншого боку, там немає нічого такого, що не можна запланувати наперед — якщо знати загальні принципи. Про це колись пізніше.
26.02.2024
embed.FS - включення файлів у програму на Go
Одна з моїх улюблених та недооцінених можливостей Go - це модуль embed. Завдяки йому можна скомпілювати в програму не тільки окремі файли, а й цілі директорії. Виглядає це приблизно так:
//go:embed resources/*.html resources/*.css
var resources embed.FS
index, err := resource.ReadFile("index.html")
У embed
є дві форми: окремий файл та директорія. Файл в програмі стає звичайним рядком: дуже зручно. А директорія перетворюється на тип embed.FS
, який сумісний з модулем io
та тому підходить для багатьох споживачів — наприклад, можна роздавати ці файли по HTTP за допомогою http.FileServerFS.
Несподівано корисним embed
є у тестах. Час від часу стає потреба завантажити до тесту допоміжні файли, які лежатимуть в той самій директорії. Але.. в якій такій тій самій, коли під час виконання ніякого вихідного коду вже немає? Добре, що тестова програма для модуля запускається саме в директорії модуля, тому можна вважати, що допоміжні файли поруч. Проте це працює тільки для файлів з того модуля, який тестується. А коли винесеш файли в інший модуль — доведеться вручну прописувати шлях. Так от, з embed
ця проблема зникає — ніяких більше відносних шляхів.
25.02.2024
Водяне охолодження — з чого воно складається?
Система водяного охолодження має форму замкненого контуру з елементів, які поєднані трубками. На відміну від побутового водопроводу, який знаходиться під тиском, в системі охолодження вода ходить по колу, а значить, розгалужень бути не може. Відповідно, в кожного елемента завжди є один вхід та один вихід. Які то компоненти?
-
Теплообмінники (waterblock) - заміняють повітряні радіатори. Це важкущий блок з металу, який притискається до мікросхем, а всередині бігає вода та забирає тепло. Практично має сенс встановити теплообмінник на процесор та на відеокарту — хоч можна знайти й блоки для інших компонентів, але то вже зайве.
-
Радіатор (radiator) - який віддаватиме тепло у навколишнє середовище. На радіаторі будуть вентилятори — такі самі, які й в повітряній системі. Радіатор найскоріше кріпиться на корпус компʼютера. Сенс всієї системи в тому, що вода ефективно передає тепло від мікросхем до радіатора, а з радіатора можна ефективно “здути” тепло назовні — замість того, щоб вибудовувати складні повітряні потоки всередині корпуса.
-
Помпа (pump) - забезпечує потік води. Помпа — це єдиний новий активний елемент. Вода в системі мусить постійно рухатись — без цього вона перегріється. З погляду програмного забезпечення, помпа — це лише ще один “вентилятор”, який регулюється стандартним розʼємом. Часто помпа поєднується з бачком.
-
Бачок (reservoir) - просто містить резерв води. Резерв потрібний, бо вода завжди випаровується. Та й взагалі дуже складно було б без бачка заповнити всю систему без пухирів повітря — а пухирів нам абсолютно не потрібно, бо з ними охолодження не буде.
Чого тут немає, так це ніяких контролерів. Водяне охолодження керується самим компʼютером так само як і вентилятори, тільки криві незвичні. А про трубки та інші зʼєднувальні компоненти можна писати ще цілий пост.
24.02.2024
Водяне охолодження ПК — що воно таке?
В мене вже третій рік ПК працює на водяному охолодженні. Весь цей час збираюся щось написати, отже, сьогодні почну.
Мій ігровий ПК стоїть в зачиненій шафці під телевізором — в режимі HTPC - проте це потужний ігровий компʼютер. З самого початку йому не вистачало охолодження. Скільки вентиляторів не додавай в корпус компʼютера, шафка все одно перетворювалась на духовку. Можна було б придумати повітрообмінник з шафи назовні, але, після довгих роздумів, я все ж вирішив піти з водяною системою.
Що ж, водяне охолодження безперечно здатне перетворити теплові потреби компʼютера на щось абсолютно нове. Я обрав зовнішній радіатор — бо задача була винести тепло за межі шафки. Таке рішення працює абсолютно беззвучно більшість часу, та набагато тихіше звичайного охолодження під час найбільш навантаженої роботи: теплова маса радіатора дає величезну фору будь-якій іншій системі охолодження.
На мою думку, водяне охолодження варто своїх коштів… але кошти підуть немаленькі. Історій про фітинги, які протікають, трубки, які розкладаються, і так далі, достатньо, щоб зрозуміти, що заощаджувати не варто. Навпаки, компоненти від надійних виробників служать довго та абсолютно без проблем. Орієнтовно, я б закладав бюджет на систему у $500 - $1000.
Окрім витрат, доведеться мати базово-просунуті навички в цілій низці галузей. Розбирати компʼютер — очевидно. Але також, зняти радіатор з відеокарти (це зовсім не така типова задача, як з процесора!). Зібрати “сантехніку” та перевірити на протікання. З зовнішньою системою — подовжувати кабелі для вентиляторів. Вішати все це на стіну. А потім ще й налаштувати програмну частину, щоб керувати швидкістю помпи та вентиляторів (бо так, є ще й помпа зі своєю фізикою).
Одним словом, хобі як дороге, так і складне. Але принаймні результат того вартий. По-перше, це красиво та рідкісно. По-друге, дозволяє не згадувати про охолодження навіть у найвибагливіших іграх. Поки на цьому все, подробиці будуть пізніше.
23.02.2024
10 днів зі стохастичним таймтрекером
Вже трохи більше як тиждень користуюся своїм таймтрекером (який паралельно дописую). Коли виправив надсилання сповіщень, то, фактично, MVP вже був готовий. Нагадаю, що на відміну від типового трекера, цей — стохастичний — самостійно опитує (“пінгує”) тебе у випадкові моменти часу — так само як це роблять статистичні профайлери коду. В середньому, раз на 45 хвилин, але на практиці бачив і раз в 3 хвилини, і 3 години без пінгів.
-
Заносити записи легко, навіть без застосунку на Apple Watch. Поки є тільки застосунок на телефон, але випадків, коли телефона немає поруч, а можливість скористатися годинником є, дуже мало. На практиці я встигаю записати понад 90% записів. Якщо відразу не запишеш, потім часто це стає неможливим, оскільки…
-
Цей трекер потребує заносити те, чим займаєшся зараз. Якщо я пишу пост, а потім перемкнувся на новини, та у цей момент прийшов пінг трекера — запишу “читав новини”. Виходить, за винятком дійсно безперервних занять, через десять хвилин точні дані вже не згадаєш.
-
CтохастичнийТаймтрекер потребує міцної віри у статистику. З простого погляду, він виглядає нечесно, бо то пропускає важливі заняття (годину стояв в тягнучці, пінгів не було) або навпаки, перебільшує дрібні (три пінги за 10 хвилин вмивання). Тому треба памʼятати, що статистично цей метод є абсолютно чесним, більш чесним, ніж коли заносиш час на свій розсуд — бо в такому разі обминаєш “дрібні” або просто неприємні відрізки (такі, як перегляд новин під час “написання посту”.) А статистичний трекер навпаки привертає до таких “дрібниць” увагу — якщо я частіше “читаю новини” ніж “пишу пост”, то це вже привід задуматись над витратами часу.
-
Вплив на свідомість: відсутність передбачуваності пінгів та потреби власноруч заносити час призводить (може призвести) до загальної підвищеної усвідомленості — не заради трекера, а заради себе. Коли памʼятаєш, що в будь-який момент може прийти пінг та доведеться записати “читаю новини”, то не так вже й хочеться багато часу на те витрачати. (Але, також буває прикро, коли три години працюєш невпинно, а пінгів немає. Не пощастило. Але не в пінгах сенс.)
Поки експеримент мені подобається, далі буде.
22.02.2024
Проблема декількох версій залежностей
Є така проблемка в проєктах на Go, що у транзитивних залежностях може бути декілька версій однієї бібліотеки. Ну, наприклад, github.com/redis/go-redis/v9
та github.com/go-redis/redis/v8
. Окрім того, що це збільшує розмір програми (та хто його лічить?) - є й ризик помилки.
(До речі, в Go предивна система версій модулів. Взагалі в Go модуль це тека. Ніякої “збірки” у .gem, .jar, чи навіть .zip немає. Назва модуля дорівнює його URL в Git. А наступна несумісна версія модуля створюється… не в теці v2
, як може це здатись, а у гілці з назвою v2
. При цьому назва модуля залишається такою самою. Мені доводилося це робити з нашою бібліотекою go-global, коли вона переїхала з AWS SDK v1 на AWS SDK v2, який цій системі не слідує.)
Коли ти оперуєш типами з пакета, легко помітити різницю між версіями, бо вони є несумісними. Але не всі операції потребують типів. Наприклад, константи помилок з різних версій пакета не проходитимуть перевірку на рівність. Та й інші нетипізовані константи. А ще глобальні налаштування на кшталт хуків — вони теж можуть піти не туди, куди треба.
Одним словом, коли значення, які за всією логікою мають збігатись, все ж розрізняються, перше, що спадає мені на думку — перевірити версії модулів.
Така сама тільки гірше проблема в JavaScript - бо там типи не допомагають, а залежностей експоненційно більше.
21.02.2024
Пара неочевидних ідіом у SwiftUI
Взагалі, помітив, що останнім часом багато натрапляю на прості, ідіоматичні рішення замість своїх ускладнених за браком знань. Вчусь, напевно. Бо буває, що ідіоматичний код очевидний, а буває навпаки, перелопатиш половину Інтернету, але на жаль не за тими пошуковими запитами.
-
Для відображення модального вікна вживається метод .sheet(isPresented:). (Це “модифікатор”, має схожу семантику до HOC у React, тобто надає компоненті нових властивостей, в цьому разі — можливість показати модал.) Типовий сценарій — модал редагування — потребує також вибору елементу, який зʼявиться в модалі. Тобто потрібно було мати дві змінні стану — видимість та елемент — та ще й синхронізувати їх поведінку. Дізнався, що є й інша форма цього методу: .sheet(item: $itemToEdit). Тут модал стане видимим, коли
$itemToEdit != nil
, та автоматично присвоїть їйnil
при закритті вікна (Синтаксис з доларом$
- це “привʼязка” - тобто спосіб передати посилання на значення, здатне на запис.) -
Є такий компонент
List
, який виводить всілякі списки (Більша частина інтерфейсу iOS - списки різного роду. Форми це теж списки, до речі. ) Список може бути пласким, може — секційним. Але що, коли треба показати ієрархічний список — наприклад, файлову систему? В інтернеті знаходив багато рішень, від вкладенихList
до обчислення вірних відступів за горизонталлю. Проте сам компонентList
має режим з вкладеністю. Якщо передати аргумент children. Як це працює — бо “дітей” треба буде брати у кожного елементу, та ще й з вкладеністю? Уchildren
ми передаємо шлях атрибута (key-path), за якимList
зможе знайти дітей кожного конкретного елементу. Досить екзотична фішка Swift, як на мене.
20.02.2024
Операції з часом в OpenSearch
Поступово дізнаюся нові можливості OpenSearch (та ElasticSearch), які, хоч і базові, але чомусь на поверхні не лежать. Сьогодні — про те, що дати набагато гнучкіше, ніж я собі думав.
Взагалі OpenSearch зберігає дати як числа. Проте, як я розумію з коду, різниця в індексації є: як я писав, числа OpenSearch індексує деревом множин, щоб швидше шукати за діапазоном. Для дат ці множини будуються не аби як, а за одиницями часу: хвилинами, годинами й так далі: ось код. Звісно, це саме те, чого ми хочемо від пошуку за часом.
Але це таке, знати не потрібно. А що варто знати, так це те, що час можна вказати зі скругленням до потрібної одиниці. Наприклад, потрібно мені знайти записи за останній тиждень. Як вказати верхню межу? Відома проблема, що просто датою не можна — відбитки часу за останню дату будуть технічно більші за дату без часу. Тому можна вдаватись до хаків: написати 23:59:59
(і втратити відбитки за останню хвилину!), чи зробити строго менше наступної дати. Проте в OpenSearch можна просто зробити запит зі скругленням до дня:
{
"range": {
"timestamp": {
"gte": "2024-02-12||/d",
"lte": "2024-02-18||/d"
}
}
}
(Ба більше, в цьому прикладі можна було б скруглити до тижня та ще спростити собі роботу.)
Та й повертати значення дати можна відразу в такому форматі, як нам потрібно: для документів з пошуку є опція docvalue_fields
(дивна назва), а для агрегацій за датою просто format
. Трохи незвично таке робити в базі, бо я звик, що бібліотека-клієнт віддає обʼєкти дати, з якими вже робиш що хочеш — проте за відсутністю такої бібліотеки дуже зручно.