01Огляд проєкту
Kyndsy — мобільний застосунок, що відповідає на питання, на яке майже ніхто не може відповісти про себе сам: як я насправді говорю? Він чує голос власника у звичайній розмові й рахує грубі вислови, ввічливі, слова-паразити та моменти, коли тон стає різким. Показує динаміку по днях і тижнях. І на цьому зупиняється — він не каже людині, якою людиною її це робить.
Задум у тому, що застосунки для саморозвитку здебільшого малюють графік вашої ж думки. Ви звітуєте про день, вони візуалізують звіт. Kyndsy починає з того, з чим складніше сперечатися: зі слів, які справді були сказані, порахованих, поки людина була зайнята життям, а не сіла рефлексувати.
Це ж робить продукт важким. Рахувати мовлення означає ввімкнути мікрофон, а мікрофон означає, що людина має довіряти застосунку більше, ніж майже всьому іншому в телефоні. Тому весь продукт побудований навколо обіцянки, яка зобов'язана бути будовою, а не текстом: звук не зберігається, слова не записуються, чужі голоси не розбираються, і немає облікового запису, до якого все це можна було б прив'язати.
Ми зробили все: застосунок для iOS та Android, вміст тридцятьма мовами, легкий сервер, шлях випуску в магазини й сайт продукту. Нижче — завдання, рішення і те, що ми свідомо відмовилися робити.
02Контекст і завдання
Застосунок, який слухає, — це галузь, де очевидна реалізація водночас неправильна. Розбір завдання дав набір обмежень, які визначили все подальше.
- Довіра і є продукт. У застосунку, що вимірює мовлення, рівно один актив, і це не алгоритм. Якщо людина запідозрить, що звук іде з телефона, точність не врятує — вона видалить застосунок.
- Оточення ні на що не погоджувалося. Мікрофон у кімнаті чує всіх, хто в ній є. Розбір мовлення людей навколо власника — це інший застосунок, і значно гірший.
- Число про людину небезпечне. Будь-яка єдина оцінка, що претендує описати людину, — твердження, якого продукт не може чесно зробити; і її прочитають як вирок, хоч би що було написано поруч дрібним шрифтом.
- Сирі лічильники брешуть. «Ви вилаялися дев'ять разів» заохочує мовчання: той, хто нічого не казав, має вигляд людини, яка виправилася.
- Слова неоднозначні. Те саме слово — жарт, цитата, скарга на себе чи справжня образа, залежно від тону й контексту. Рахунок за рядком дає числа, у яких ніхто не впізнає свого дня.
- Люди говорять не однією мовою. Вони перемикаються посеред фрази. Лічильник, що йде лише за однією мовою, відзвітує підозріло спокійним днем щоразу, коли власник перейшов на іншу.
- У магазинів є правила про мікрофон, про твердження щодо здоров'я та психології і про те, що взагалі може закривати підписка, — і перевіряються вони на поданні, а не в день запуску.
Усе це мало працювати на телефоні, у фоні, не з'їдаючи ні батареї, ні терпіння людини.
03Цілі проєкту
- Рахувати мовлення на пристрої. Розбір іде на телефоні; звук не зберігається і не вивантажується.
- Тільки голос власника. Чужі голоси відкидаються, а не розбираються, і режиму «спрямувати застосунок на іншу людину» не існує.
- Ані облікового запису, ані імені. Витікати нічому, бо збирати нічого.
- Частки, а не сирі лічильники. Усе на тисячу сказаних слів, щоб тихий день лишався тихим днем, а не досягненням.
- Тридцять мов, включно зі змішаним мовленням — словники мають існувати в усіх одразу, інакше число бреше тим, хто перемикається.
- Розрізняти відтінки. Іронія, сарказм, жарт і справжня різкість розведені й позначені як здогад, а не як вирок.
- Корисно й без мікрофона. Щоденник, компас цінностей, тести й вечірні питання працюють самі по собі.
- Мотивація, яку не можна обіграти. Серії, рівні та програми оцінюються вимірюванням, а не відкриттям застосунку.
- Жодної загальної оцінки людини. Ані в першій версії, ані потім.
04Що ми зробили
Застосунок улаштований як чотири місця, кожне відповідає на своє питання, плюс те, що їх тримає:
- Сьогодні — що щойно було: показник мовлення, цілі дня і одна підказка, а не список із шести.
- Прогрес — чи йде це кудись: серії, рівні, програми і тижневий звіт.
- Компас — на що людина вирішила орієнтуватися: три-п'ять цінностей, обраних нею самою, і рух до них.
- Ви — усе, що належить лише їй: тести самоперевірки, сімейний доступ, свої дані й підтримка.
Знизу лежить те, що робить ці чотири місця чесними: розбір мовлення на пристрої, словники й правила для тридцяти мов, визначення відтінків, модель рахунку в частках, а не в підсумках, легкий сервер, який майже нічого не знає, і реєстр налаштувань, що дозволяє змінювати продукт без випуску в магазині.
05Приватність — це код, а не текст
Обіцянки приватності на сайті — не рекламний текст, який наступна оптимізація може тихо зробити неправдою. Це властивості збірки, і правка, що робить будь-яку з них хибною, вважається в проєкті дефектом, а не розміном.
- Звук нікуди не пишеться — ані у файл, ані у тимчасовий буфер на диску, ані в журнал. І у зневаджувальній збірці теж, бо саме так такі речі й витікають.
- Розбирається лише голос власника. Чуже мовлення відкидається до того, як із нього вийдуть слова.
- Розшифровки немає. Застосунок виробляє лічильники, а не текст; немає збереженої фрази, яку можна було б отримати на запит або випадково синхронізувати.
- Сесію запускає лише людина. Ані автозапуску після перезавантаження, ані тихого відновлення у фоні.
- Голосовий профіль не покидає телефон і виключений із резервних копій — це біометричні дані, а копія якраз те місце, про яке забувають.
- Серверу кажуть чотири речі й не більше: запит налаштувань, разове завантаження моделей, звернення до підтримки, якщо людина сама його написала, і чек підписки. Облікового запису немає.
- Людина — це пара випадкових чисел, вигаданих її ж телефоном. Ми їх не видаємо і не рахуємо — а отже, не знаємо кількості встановлень, і це була свідома ціна.
- Вхід необов'язковий і нічого не відкриває. Він потрібен, щоб перенести підписку й історію на новий телефон. Обов'язковий вхід створив би зв'язок зі справжнім обліковим записом там, де його зараз немає.
На останньому пункті варто затриматися. Вимога власника була — знати лише анонімний ідентифікатор, і спокусливий спосіб її виконати це обов'язковий вхід, який ми потім обіцяємо не читати. Ми зробили навпаки: облікового запису немає взагалі, а необов'язковий вхід читає з токена рівно одне поле й зберігає його хешем.
06Що саме рахує застосунок
Чотири речі: грубі вислови, ввічливі вислови, слова-паразити та піднятий, різкий тон. Усе це показується на тисячу сказаних слів, а не сирим підсумком: сирий лічильник робить мовчання схожим на прогрес, а застосунок, який нагороджує власника за те, що він мовчав, не зрозумів власної роботи.
Заголовок дня — індекс шанобливого мовлення, і правила навколо нього продумані не менше за саме число:
- Він повністю прихований, поки не почуто п'ятдесяти слів. Нуль у тихий ранок читається як звинувачення, а не як відсутність даних.
- Дні, де слів менше за п'ятдесят, показуються, але не рахуються — видні порожніми, а не вдають хороший день.
- Ввічливість піднімає індекс не більш як на десять пунктів. Далі показник було б дешевше набрати люб'язностями, ніж заробити відсутністю різкості.
- Будь-яку подію можна позначити як помилкову, і це змінює число, а не просто викреслює рядок зі списку.
Види поверх цього звичайні за формою і уважні в дрібницях: тижневий тренд, картина дня по годинах, тридцятиденна сітка по квадрату на день. Годинний вид відмовляється оголошувати «найгіршу годину», поки в нього немає десяти подій; тридцятиденна сітка лишає тихі дні бежевими, а не фарбує їх у спокійні. Графіки, впевнені на тонких даних, — це спосіб, яким продукт-вимірювач втрачає довіру читача, зазвичай назавжди.
07Відтінки мовлення: іронія, жарт, укол
Жарт і образа — не те саме слово двічі. Kyndsy відділяє іронію від справжньої різкості, жарт від уколу, цитату від того, що людина мала на увазі, — і показує словами, що йому почулося, поруч із подією.
Чесність цієї функції тримають два правила. Перше: це здогад, а не вирок — застосунок пише «можливо, іронія» або «жарт — не зараховано» і показує, на чому ґрунтувався. Друге, і важливіше: відтінок ніколи не рухає індекс. Він повідомляє людині, але не підкручує її показник мовчки. Число, зважене за впевненістю, ніхто не зміг би перевірити, і воно швидко стало б найспірнішою функцією продукту.
Так само акуратно влаштований контекст: те саме слово рахується по-різному, коли людина когось цитує, говорить про себе або перебуває посеред суперечки. А оскільки жоден словник не знає, що чиїсь слова означають особисто для неї, у людини є власні списки.
08Тридцять мов — і змішане мовлення
Застосунок працює тридцятьма мовами — англійська, іспанська, португальська, німецька, французька, італійська, нідерландська, шведська, данська, норвезька, фінська, польська, чеська, хорватська, румунська, угорська, грецька, турецька, російська, українська, білоруська, іврит, арабська, гінді, індонезійська, в'єтнамська, тайська, китайська, японська і корейська — і кількома одразу, бо дуже багато людей саме так і говорять.
Тридцять мов — це не тридцять перекладів інтерфейсу. Це тридцять наборів словників (грубі вислови, ввічливі звороти, паразити), і з'являтися вони зобов'язані одночасно. Мова з недоробленим словником не падає гучно — вона звітує спокійним днем. Людина бачить хороше число і вірить йому, а це гірше за повідомлення про помилку.
Один урок цього проєкту виходить далеко за його межі: ознака, вгадана за виглядом тексту, ламається на першій же мові з іншою писемністю. Вважати «зворотом» рядок із пробілом працює рівно до японської, китайської й тайської, які пишуться без пробілів, — і там застосунок не знаходить нічого, мовчки, продовжуючи мати вигляд працюючого. Поведінка мови має братися з даних самої мови, і вона зобов'язана бути закрита тестом одразу по всіх тридцяти.
09Компас і щоденник
Мовлення — лише половина продукту. Друга половина — те, на що людина вирішила орієнтуватися: вона обирає три-п'ять цінностей із семи (повага, чесність, самовладання, відповідальність, турбота, справедливість, надійність), і застосунок показує рух до них, а не до чийогось чужого уявлення про хорошу людину.
Рух складається з двох джерел: вимірювань мовлення і власного щоденника вчинків — дотримав обіцянку, вибачився, зірвався, виправив. Плюс три питання наприкінці дня, коли вони потрібні.
Загальної оцінки моральності немає — ані зараз, ані потім. Це єдине, що продукт відмовляється обчислювати. І саме тому компас працює: чесні цінності людина обере лише для застосунку, який не збирається ставити їй за них оцінку.
Усе в цій половині працює без мікрофона. Щоденник, компас, тести й вечірні питання стоять самі по собі, тож голосову частину можна налаштувати пізніше або ніколи — і застосунок усе одно лишиться корисним. Це продуктове рішення зі справжніми наслідками для утримання, і ми ухвалили б його знову: запит дозволу на першому екрані — те місце, де застосунок про приватність втрачає тих, заради кого його писали.
10Програми, серії та тижневий звіт
Мотивація тут зобов'язана була бути несприйнятливою до двох звичних обходів: часто відкривати застосунок і нічого не говорити. Тому:
- Програми тривають від 7 до 30 днів з однією метою й одним числом — тиждень без грубих слів, м'якше відповідати два тижні, менше паразитів за місяць. Спрацювало чи ні, вирішують вимірювання, а не галочка.
- Серія рахує дні, у які людина справді втримала рівень. Тихі дні її не рвуть і не продовжують — прибрати телефон не спосіб виграти.
- Рівні заробляються днями, а не відкриттями застосунку: Спостереження, Контроль, Спокійне мовлення.
- Щити закривають зрив, але не безмежно, а зірваний день можна викупити — тільки серія з тридцяти днів, чотири з яких куплені, це не серія з тридцяти днів, тому такі дні рахуються й показуються окремо.
- Тижневий звіт прямо каже, коли порівнювати немає з чим. Зведення, у якому завжди щось покращилося, перестає читатися до третього тижня.
Варто назвати одну навмисну асиметрію: безкоштовний рівень обмежує показ історії, а не рахунок. Рахувати серію лише за видимим вікном означало б показувати тридцятиденну серію як семиденну — це не обмеження безкоштовного тарифу, а неправда про людину.
11Сто тестів самоперевірки
Поруч із вимірюваннями лежить сотня структурованих тестів самоперевірки: по двадцять п'ять тверджень, близько чотирьох хвилин, п'ять граней оцінюються окремо, тому відповідь ніколи не зводиться до одного плаского числа. Теми — мовлення, почуття, близькі, робота, ви самі, звички і життя в мережі.
Це явно не діагнози й не вимірювання особистості — це структурована саморефлексія, і застосунок каже про це там, де людина прочитає, а не в налаштуваннях. Відповіді лишаються на телефоні, як і все інше.
Інженерний сенс тут у тому, що сотню тестів не можна вести як сотню написаних руками екранів. Вони лежать ресурсом, а не кодом: збираються з джерел, перевіряються на збірці й відкидаються, якщо в тесту немає повного набору тверджень і граней. Саме ця перевірка робить можливим мати їх сто, і вона ж дозволила роздати правила відкриття однаково, а не розставити руками.
Половина відкривається працею, половина купується. Товарів під платну половину навмисне небагато, а не по одному на тест: сотню позицій у магазинах ніхто не заведе руками і ніхто не перекладе тридцятьма мовами. Продається відкриття; який саме тест на нього витратити, людина обирає в застосунку вже після підтвердження покупки.
12Підписка, сім'я та магазини
Платний рівень — підписка, і сім'я її ділить: шість місць на рік, включно з місцем покупця. Важливо, що саме ділить сім'я і чого не ділить: сім'я ділить право, а не дані. Ніхто не бачить чужих чисел, подій і щоденника, а той, хто оплатив, бачить вільні місця й дати, а не те, хто їх зайняв.
Це не застереження дрібним шрифтом, а будова: чужих показників на сервері немає взагалі, тому в сімейному екрані нема чого випадково розкрити. Вводячи код, людина погоджується розділити підписку, а не назватися.
Два правила з цієї частини пережили саму функцію. Перше: підписка й сімейне право — один прапорець у застосунку; друге питання на кшталт «а може, він у сім'ї» забули б рівно там, де воно важливе. Друге: мовчання сервера право не знімає — мережа зникає значно частіше, ніж закінчується підписка, і застосунок, що замикає платящу людину в потязі, зробив очевидний вибір погано.
Правила магазинів визначили тут багато що: що має право стверджувати застосунок із мікрофоном, як можна показувати платний рівень і те, що зламану збірку не відкотиш хотфіксом. Тому політика версій — мінімальна підтримувана версія, вимога оновитися, режим обслуговування і текст повідомлення всіма мовами проєкту одразу — це серверне налаштування, а не те, що вкомпільоване всередину.
13Архітектура: застосунок, сервер, реєстр
Архітектура випливає з обіцянки приватності: якомога більше на телефоні, якомога менше на сервері.
- Застосунок веде розбір, зберігає історію і володіє голосовим профілем. Він і є продукт; сервер тут на підхваті.
- Легкий сервер відповідає на чотири види запитів — налаштування, разове завантаження моделей, звернення до підтримки і чеки підписки. Таблиці користувачів у нього немає, бо немає користувачів, яких туди класти.
- Реєстр налаштувань тримає те, що інакше було б зашите в застосунок: ідентифікатор пакета, адресу API, параметри входу, список мов, прапорці функцій і політику версій. Значення не пишуться у джерела руками, а генеруються в них, і згенерований файл позначено «не правити» з простої причини: ручна правка губиться при наступній генерації.
- Передпольотна перевірка стоїть гейтом перед кожною збіркою: вона відмовляє, якщо ідентифікатор пакета розійшовся з реєстром, якщо версія не вища за зібрану, якщо сервер застосунку не відповідає, якщо словник неповний хоч однією мовою проєкту, якщо статичний аналіз не чистий, якщо падають тести або якщо в джерелах знайшлося схоже на ключ. Вона повертає ненульовий код, тому годиться гейтом у будь-якому CI.
- Платний рівень стоїть за прапорцем, який гаситься без перезбирання і без нової версії в магазині.
Сайт — невеликий PHP-застосунок без власної бази, окрім листування підтримки: той самий принцип, застосований на рівень вище.
14Технологічний стек
- Flutter для iOS та Android з одного коду — з дизайн-системою в коді, щоб колір, відступ і заокруглення задавалися в одному місці, а не в кожного віджета.
- Розпізнавання мовлення й розбір на пристрої: моделі завантажуються один раз і працюють локально, а маніфест з їхніми розмірами й хешами будується з файлів, а не пишеться руками.
- PHP 8.4 для сервера застосунку й сайту, з невеликою базою лише під листування підтримки.
- Реєстр налаштувань як джерело істини для параметрів застосунку, з генерацією коду і передпольотним гейтом.
- Тридцять мовних наборів у застосунку і три на сайті, з паритетом словників, який тримають тести, а не рев'ю.
- Сувора політика безпеки вмісту на сайті — жодного інлайнового стилю, обчислювані значення збираються в окрему таблицю стилів, шрифт свій: сторінка про приватність не тягне жодного чужого ресурсу.
15Дизайн і UX
Візуальна мова — одна темна тема, знята з сайту продукту, щоб людина відкривала рівно те, що їй обіцяли. Світлий варіант написаний у токенах і навмисне не підключений: дві теми означають два набори знімків і вдвічі більше місць, де верстка ламається непомітно.
Колір, відступ і заокруглення живуть в одному файлі дизайну, а перехід із тривожного кольору в спокійний іде через теплий жовтий: навпростець середина дає оливкову бруднь — те, що має вигляд недбалості, а насправді є пропущеною опорною точкою.
У застосунку є персонаж, і правила навколо нього не так про чарівність, як про чесність: настрій читається силуетом, а не лише кольором, тому дальтонік бачить те саме, що всі; настрій — неперервна шкала з анімацією між значеннями, а не п'ять готових картинок, бо стрибок читається як інша картинка, а не як той самий герой; а при тривозі брови йдуть внутрішніми кінцями вгору, бо опущені всередину — це злість на того, хто дивиться.
В усьому іншому інтерфейс дотримується головного правила продукту: показувати виміряне, казати вголос, коли сказати нема чого, і ніколи не зводити людину до одного числа.
16Як ми працювали
- Спочатку обіцянка. Ми записали, чого застосунок не робитиме ніколи — зберігати звук, розбирати оточення, питати, хто ви, оцінювати вас як людину, — до всякого проєктування: ці рішення обмежують архітектуру, а не випливають із неї.
- Ядро вимірювання. Розбір на пристрої, рахунок у частках, індекс із його порогами й відмовою з'являтися на тонких даних.
- Мовна робота. Тридцять словників і правил, з паритетом, закритим тестами одразу по всіх.
- Друга половина. Компас, щоденник, програми, серії, тижневий звіт — усе, що працює без мікрофона.
- Тести як ресурс. Сотня тестів самоперевірки, які збираються й перевіряються, з драбиною відкриття, яку роздає збирач.
- Монетизація. Підписка, сім'я, невеликий набір товарів у магазинах і платний рівень за прапорцем.
- Шлях випуску. Реєстр, генерована конфігурація, передпольотний гейт, реєстрація збірок і політика версій.
- Сайт. Три мови, сувора політика безпеки вмісту і лендинг, що показує справжні екрани застосунку.
Дві речі поверталися під час роботи постійно, і обидві стали правилами. Усе, що інтерфейс стверджує про поведінку людини, зобов'язане перевірятися вимірюванням; усе, що застосунок обіцяє про приватність, зобов'язане триматися кодом, а не нотаткою в документі — домовленість живе рівно до наступного, хто її не прочитав.
17Результат
Вийшов вимірювальний продукт для того, про що зазвичай лише здогадуються, — влаштований так, що вимірювання не коштує людині приватності.
- Розбір мовлення на пристрої: нічого не записується, нічого не розшифровується, чужі голоси відкидаються.
- Усе показується на тисячу слів, тому мовчання не сприймають за прогрес.
- Іронія, сарказм і жарти розведені — і позначені як здогад, що не рухає показника.
- Тридцять мов зі словниками, які з'являються одночасно, і тестами одразу по всіх.
- Компас цінностей, щоденник, програми і тижневий звіт, який визнає, коли порівнювати немає з чим.
- Сотня тестів як перевірювані ресурси і невеликий підтримуваний набір товарів під платну половину.
- Сімейний тариф, який ділить підписку і нічого більше — бо даних на сервері немає.
18Висновки
Kyndsy — проєкт, де найважча інженерія була в обмеженнях. Розбір на пристрої, відсутність розшифровки, відсутність облікового запису, відмова від загальної оцінки, відмова розбирати оточення — кожне з них ускладнювало збірку і робило продукт можливим. Версія цього застосунку із серверним конвеєром і логіном писалася б швидше і не заслуговувала б на чийсь мікрофон.
Урок, який ми забираємо, — про те, як тримаються обіцянки: гарантія, що живе в документі, — гарантія рівно до наступної правки, яку з нею не звірили. Тут витримали ті, що виражені кодом і закриті тестами: паритет по тридцяти мовах, контраст, перевірюваний числом, а не поглядом, рух, перевірюваний значеннями, а не знімком, і гейт збірки, який відмовляє, а не попереджає.
Якщо ви робите мобільний продукт, де приватність — це функція, а не застереження; щось, що зобов'язане працювати одразу багатьма мовами; або застосунок, числам якого люди мають вірити про себе, — таку роботу ми ведемо від задуму до магазину.
